#undef NDEBUG
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include <ctype.h>
#include <lcthw/dbg.h>
#include <lcthw/bstrlib.h>

/*
 * This source file is part of the bstring string library.  This code was
 * written by Paul Hsieh in 2002-2010, and is covered by either the 3-clause 
 * BSD open source license or GPL v2.0. Refer to the accompanying documentation 
 * for details on usage and license.
 */ 
static bstring dumpOut[16];
static int rot = 0;
static char *dumpBstring(const struct tagbstring *b)
{
    rot = (rot + 1) % (unsigned)16;
    if (dumpOut[rot] == NULL) {
        dumpOut[rot] = bfromcstr("");
        if (dumpOut[rot] == NULL)
            return "FATAL INTERNAL ERROR";
    }
    dumpOut[rot]->slen = 0;
    if (b == NULL) {
        bcatcstr(dumpOut[rot], "NULL");
    } else {
        static char msg[256];
        sprintf(msg, "%p", (void *)b);
        bcatcstr(dumpOut[rot], msg);
        if (b->slen < 0) {
            sprintf(msg, ":[err:slen=%d<0]", b->slen);
            bcatcstr(dumpOut[rot], msg);
        } else {
            if (b->mlen > 0 && b->mlen < b->slen) {
                sprintf(msg, ":[err:mlen=%d<slen=%d]", b->mlen,
                        b->slen);
                bcatcstr(dumpOut[rot], msg);
            } else {
                if (b->mlen == -1) {
                    bcatcstr(dumpOut[rot], "[p]");
                } else if (b->mlen < 0) {
                    bcatcstr(dumpOut[rot], "[c]");
                }
                bcatcstr(dumpOut[rot], ":");
                if (b->data == NULL) {
                    bcatcstr(dumpOut[rot], "[err:data=NULL]");
                } else {
                    bcatcstr(dumpOut[rot], "\"");
                    bcatcstr(dumpOut[rot], (const char *)b->data);
                    bcatcstr(dumpOut[rot], "\"");
                } } } } return (char *)dumpOut[rot]->data;
}  static int test0_0(const char *s, const char *res)
{
    bstring b0 = bfromcstr(s);
    int ret = 0;
    if (s == NULL) {
        if (res != NULL)
            ret++;
        debug(".\tbfromcstr (NULL) = %s", dumpBstring(b0));
        return ret;
    }
    ret += (res == NULL) || ((int)strlen(res) != b0->slen) 
        ||(0 != memcmp(res, b0->data, b0->slen));
    ret += b0->data[b0->slen] != '\0';
    debug(".\tbfromcstr (\"%s\") = %s", s, dumpBstring(b0));
    bdestroy(b0);
    return ret;
}

static int test0_1(const char *s, int len, const char *res)
{
    bstring b0 = bfromcstralloc(len, s);
    int ret = 0;
    if (s == NULL) {
        if (res != NULL)
            ret++;
        debug(".\tbfromcstralloc (*, NULL) = %s", dumpBstring(b0));
        return ret;
    }
    ret += (res == NULL) || ((int)strlen(res) != b0->slen) 
        ||(0 != memcmp(res, b0->data, b0->slen));
    ret += b0->data[b0->slen] != '\0';
    ret += len > b0->mlen;
    debug(".\tbfromcstralloc (%d, \"%s\") = %s", len, s,
            dumpBstring(b0));
    bdestroy(b0);
    return ret;
}


#define EMPTY_STRING ""
#define SHORT_STRING "bogus"
#define LONG_STRING  "This is a bogus but reasonably long string.  Just long enough to cause some mallocing."
static int test0(void)
{
    int ret = 0;
    debug("TEST: bstring bfromcstr (const char * str);");

    /* tests with NULL */ 
    ret += test0_0(NULL, NULL);

    /* normal operation tests */ 
    ret += test0_0(EMPTY_STRING, EMPTY_STRING);
    ret += test0_0(SHORT_STRING, SHORT_STRING);
    ret += test0_0(LONG_STRING, LONG_STRING);
    debug("\t# failures: %d", ret);
    debug
        ("TEST: bstring bfromcstralloc (int len, const char * str);");

    /* tests with NULL */ 
    ret += test0_1(NULL, 0, NULL);
    ret += test0_1(NULL, 30, NULL);

    /* normal operation tests */ 
    ret += test0_1(EMPTY_STRING, 0, EMPTY_STRING);
    ret += test0_1(EMPTY_STRING, 30, EMPTY_STRING);
    ret += test0_1(SHORT_STRING, 0, SHORT_STRING);
    ret += test0_1(SHORT_STRING, 30, SHORT_STRING);
    ret += test0_1(LONG_STRING, 0, LONG_STRING);
    ret += test0_1(LONG_STRING, 30, LONG_STRING);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test1_0(const void *blk, int len, const char *res)
{
    bstring b0 = blk2bstr(blk, len);
    int ret = 0;
    if (b0 == NULL) {
        if (res != NULL)
            ret++;
        debug(".\tblk2bstr (NULL, len=%d) = %s", len, dumpBstring(b0));
    } else {
        ret += (res == NULL) || (len != b0->slen) 
            ||(0 != memcmp(res, b0->data, len));
        ret += b0->data[b0->slen] != '\0';
        debug(".\tblk2bstr (blk=%p, len=%d) = %s", blk, len,
                dumpBstring(b0));
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    bdestroy(b0);
    return ret;
}

static int test1(void)
{
    int ret = 0;
    debug("TEST: bstring blk2bstr (const void * blk, int len);");

    /* tests with NULL */ 
    ret += test1_0(NULL, 10, NULL);
    ret += test1_0(NULL, 0, NULL);
    ret += test1_0(NULL, -1, NULL);

    /* normal operation tests */ 
    ret +=
        test1_0(SHORT_STRING, sizeof(SHORT_STRING) - 1, SHORT_STRING);
    ret += test1_0(LONG_STRING, sizeof(LONG_STRING) - 1, LONG_STRING);
    ret += test1_0(LONG_STRING, 5, "This ");
    ret += test1_0(LONG_STRING, 0, "");
    ret += test1_0(LONG_STRING, -1, NULL);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test2_0(const_bstring b, char z, const unsigned char *res)
{
    char *s = bstr2cstr(b, z);
    int ret = 0;
    if (s == NULL) {
        if (res != NULL)
            ret++;
        debug(".\tbstr2cstr (%s, %02X) = NULL", dumpBstring(b), z);
        bcstrfree(s);
        return ret;
    }
    if (res == NULL)
        ret++;

    else {
        if (z != '\0')
            if ((int)strlen(s) != b->slen)
                ret++;
        if (!ret) {
            ret += (0 != memcmp(res, b->data, b->slen));
        }
    }
    debug(".\tbstr2cstr (%s, %02X) = \"%s\"", dumpBstring(b), z, s);
    bcstrfree(s);
    return ret;
}

struct tagbstring emptyBstring = bsStatic("");
struct tagbstring shortBstring = bsStatic("bogus");
struct tagbstring longBstring =
bsStatic
("This is a bogus but reasonably long string.  Just long enough to cause some mallocing.");
struct tagbstring badBstring1 = { 8, 4, NULL };
struct tagbstring badBstring2 = { 2, -5, (unsigned char *)"bogus" };
struct tagbstring badBstring3 = { 2, 5, (unsigned char *)"bogus" };

struct tagbstring xxxxxBstring = bsStatic("xxxxx");
static int test2(void)
{
    int ret = 0;
    debug("TEST: char * bstr2cstr (const_bstring s, char z);");

    /* tests with NULL */ 
    ret += test2_0(NULL, (char)'?', NULL);

    /* normal operation tests */ 
    ret += test2_0(&emptyBstring, (char)'?', emptyBstring.data);
    ret += test2_0(&shortBstring, (char)'?', shortBstring.data);
    ret += test2_0(&longBstring, (char)'?', longBstring.data);
    ret += test2_0(&badBstring1, (char)'?', NULL);
    ret += test2_0(&badBstring2, (char)'?', NULL);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test3_0(const_bstring b)
{
    bstring b0 = bstrcpy(b);
    int ret = 0;
    debug(".\tbstrcpy (%s) = %s", dumpBstring(b), dumpBstring(b0));
    if (b0 == NULL) {
        if (b != NULL && b->data != NULL && b->slen >= 0)
            ret++;
    } else {
        ret += (b == NULL) || (b->slen != b0->slen) 
            ||(0 != memcmp(b->data, b0->data, b->slen));
        ret += b0->data[b0->slen] != '\0';
    }
    bdestroy(b0);
    return ret;
}

static int test3(void)
{
    int ret = 0;
    debug("TEST: bstring bstrcpy (const_bstring b1);");

    /* tests with NULL to make sure that there is NULL propogation */ 
    ret += test3_0(NULL);
    ret += test3_0(&badBstring1);
    ret += test3_0(&badBstring2);

    /* normal operation tests */ 
    ret += test3_0(&emptyBstring);
    ret += test3_0(&shortBstring);
    ret += test3_0(&longBstring);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test4_0(const_bstring b, int left, int len,
        const char *res)
{
    bstring b0 = bmidstr(b, left, len);
    int ret = 0;
    debug(".\tbmidstr (%s, %d, %d) = %s", dumpBstring(b), left, len,
            dumpBstring(b0));
    if (b0 == NULL) {
        if (b != NULL && b->data != NULL && b->slen >= 0 && len >= 0)
            ret++;
    } else {
        ret += (b == NULL) || (res == NULL) || (b0->slen > len
                && len >=
                0)  ||(b0->slen !=
                    (int)
                    strlen(res)) 
                ||(b0->slen > 0 && 0 != memcmp(res, b0->data, b0->slen));
        ret += b0->data[b0->slen] != '\0';
    } if (ret) {
        debug("(b == NULL)                  = %d", (b == NULL));
        debug("(res == NULL)                = %d", (res == NULL));
        debug("(b0->slen > len && len >= 0) = %d",
                (b0->slen > len && len >= 0));
        if (res)
            debug("(b0->slen != strlen (res))   = %d",
                    (b0->slen != (int)strlen(res)));
        debug
            ("(b0->slen > 0 && 0 != memcmp (res, b0->data, b0->slen) = %d",
             (b0->slen > 0 && 0 != memcmp(res, b0->data, b0->slen)));
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    bdestroy(b0);
    return ret;
}

static int test4(void)
{
    int ret = 0;
    debug
        ("TEST: bstring bmidstr (const_bstring b, int left, int len);");

    /* tests with NULL to make sure that there is NULL propogation */ 
    ret += test4_0(NULL, 0, 0, NULL);
    ret += test4_0(NULL, 0, 2, NULL);
    ret += test4_0(NULL, 0, -2, NULL);
    ret += test4_0(NULL, -5, 2, NULL);
    ret += test4_0(NULL, -5, -2, NULL);
    ret += test4_0(&badBstring1, 1, 3, NULL);
    ret += test4_0(&badBstring2, 1, 3, NULL);

    /* normal operation tests on all sorts of subranges */ 
    ret += test4_0(&emptyBstring, 0, 0, "");
    ret += test4_0(&emptyBstring, 0, -1, "");
    ret += test4_0(&emptyBstring, 1, 3, "");
    ret += test4_0(&shortBstring, 0, 0, "");
    ret += test4_0(&shortBstring, 0, -1, "");
    ret += test4_0(&shortBstring, 1, 3, "ogu");
    ret += test4_0(&shortBstring, -1, 3, "bo");
    ret += test4_0(&shortBstring, -1, 9, "bogus");
    ret += test4_0(&shortBstring, 3, -1, "");
    ret += test4_0(&shortBstring, 9, 3, "");
    debug("\t# failures: %d", ret);
    return ret;
}

static int test5_0(bstring b0, const_bstring b1, const char *res)
{
    bstring b2;
    int rv, ret = 0;
    if (b0 != NULL && b0->data != NULL && b0->slen >= 0
            && b1 != NULL && b1->data != NULL && b1->slen >= 0) {
        b2 = bstrcpy(b0);
        bwriteprotect(*b2);
        debug(".\tbconcat (%s, ", dumpBstring(b2));
        rv = bconcat(b2, b1);
        ret += (rv == 0);
        if (!biseq(b0, b2))
            ret++;
        debug("%s) = %s", dumpBstring(b1), dumpBstring(b2));
        bwriteallow(*b2);
        debug(".\tbconcat (%s, ", dumpBstring(b2));
        rv = bconcat(b2, b1);
        debug("%s) = %s", dumpBstring(b1), dumpBstring(b2));
        if (b1)
            ret += (b2->slen != b0->slen + b1->slen);
        ret += ((0 != rv) && (b1 != NULL)) || ((0 == rv)
                && (b1 == NULL));
        ret += (res == NULL)
            || ((int)strlen(res) > b2->slen)  ||(0 !=
                    memcmp(b2->data, res,
                        b2->slen));
        ret += b2->data[b2->slen] != '\0';
        bdestroy(b2);
    } else {
        ret += (BSTR_ERR != (rv = bconcat(b0, b1)));
        debug(".\tbconcat (%s, %s) = %d", dumpBstring(b0),
                dumpBstring(b1), rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test5_1(void)
{
    bstring b, c;
    struct tagbstring t;
    int i, ret;
    debug("TEST: bconcat aliasing");
    for (ret = i = 0; i < longBstring.slen; i++) {
        b = bstrcpy(&longBstring);
        c = bstrcpy(&longBstring);
        bmid2tbstr(t, b, i, longBstring.slen);
        ret += 0 != bconcat(c, &t);
        ret += 0 != bconcat(b, &t);
        ret += !biseq(b, c);
        bdestroy(b);
        bdestroy(c);
    }
    b = bfromcstr("abcd");
    c = bfromcstr("abcd");
    for (ret = i = 0; i < 100; i++) {
        bmid2tbstr(t, b, 0, 3);
        ret += 0 != bcatcstr(c, "abc");
        ret += 0 != bconcat(b, &t);
        ret += !biseq(b, c);
    }
    bdestroy(b);
    bdestroy(c);
    if (ret) {
        debug("\t\talias failures(%d) = %d", __LINE__, ret);
    }
    return ret;
}

static int test5(void)
{
    int ret = 0;
    debug("TEST: int bconcat (bstring b0, const_bstring b1);");

    /* tests with NULL */ 
    ret += test5_0(NULL, NULL, NULL);
    ret += test5_0(NULL, &emptyBstring, NULL);
    ret += test5_0(&emptyBstring, NULL, "");
    ret += test5_0(&emptyBstring, &badBstring1, NULL);
    ret += test5_0(&emptyBstring, &badBstring2, NULL);
    ret += test5_0(&badBstring1, &emptyBstring, NULL);
    ret += test5_0(&badBstring2, &emptyBstring, NULL);

    /* normal operation tests on all sorts of subranges */ 
    ret += test5_0(&emptyBstring, &emptyBstring, "");
    ret += test5_0(&emptyBstring, &shortBstring, "bogus");
    ret += test5_0(&shortBstring, &emptyBstring, "bogus");
    ret += test5_0(&shortBstring, &shortBstring, "bogusbogus");
    ret += test5_1();
    debug("\t# failures: %d", ret);
    return ret;
}

static int test6_0(bstring b, char c, const char *res)
{
    bstring b0;
    int rv, ret = 0;
    if (b != NULL && b->data != NULL && b->slen >= 0) {
        b0 = bstrcpy(b);
        bwriteprotect(*b0);
        rv = bconchar(b0, c);
        ret += (rv == 0);
        if (!biseq(b0, b))
            ret++;
        debug(".\tbconchar (%s, %c) = %s", dumpBstring(b), c,
                dumpBstring(b0));
        bwriteallow(*b0);
        rv = bconchar(b0, c);
        ret += (0 != rv);
        ret += (b0->slen != b->slen + 1);
        ret += (res == NULL) || ((int)strlen(res) > b0->slen) 
            ||(0 != memcmp(b0->data, res, b0->slen));
        ret += b0->data[b0->slen] != '\0';
        debug(".\tbconchar (%s, %c) = %s", dumpBstring(b), c,
                dumpBstring(b0));
        bdestroy(b0);
    } else {
        ret += (BSTR_ERR != (rv = bconchar(b, c)));
        debug(".\tbconchar (%s, %c) = %d", dumpBstring(b), c, rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test6(void)
{
    int ret = 0;
    debug("TEST: int bconchar (bstring b, char c);");

    /* tests with NULL */ 
    ret += test6_0(NULL, (char)'x', NULL);
    ret += test6_0(&badBstring1, (char)'x', NULL);
    ret += test6_0(&badBstring2, (char)'x', NULL);

    /* normal operation tests on all sorts of subranges */ 
    ret += test6_0(&emptyBstring, (char)'x', "x");
    ret += test6_0(&shortBstring, (char)'x', "bogusx");
    debug("\t# failures: %d", ret);
    return ret;
}

static int test7x8_0(char *fnname,
        int (*fnptr) (const struct tagbstring *,
            const struct tagbstring *),
        const struct tagbstring *b0,
        const struct tagbstring *b1, int res)
{
    int rv, ret = 0;
    ret += (res != (rv = fnptr(b0, b1)));
    debug(".\t%s (%s, %s) = %d", fnname, dumpBstring(b0),
            dumpBstring(b1), rv);
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %d)", __LINE__, ret, res);
    }
    return ret;
}

static int test7x8(char *fnname,
        int (*fnptr) (const struct tagbstring *,
            const struct tagbstring *),
        int retFail, int retLT, int retGT, int retEQ)
{
    int ret = 0;
    debug("TEST: int %s (const_bstring b0, const_bstring b1);",
            fnname);

    /* tests with NULL */ 
    ret += test7x8_0(fnname, fnptr, NULL, NULL, retFail);
    ret += test7x8_0(fnname, fnptr, &emptyBstring, NULL, retFail);
    ret += test7x8_0(fnname, fnptr, NULL, &emptyBstring, retFail);
    ret += test7x8_0(fnname, fnptr, &shortBstring, NULL, retFail);
    ret += test7x8_0(fnname, fnptr, NULL, &shortBstring, retFail);
    ret +=
        test7x8_0(fnname, fnptr, &badBstring1, &badBstring1, retFail);
    ret +=
        test7x8_0(fnname, fnptr, &badBstring2, &badBstring2, retFail);
    ret +=
        test7x8_0(fnname, fnptr, &shortBstring, &badBstring2, retFail);
    ret +=
        test7x8_0(fnname, fnptr, &badBstring2, &shortBstring, retFail);

    /* normal operation tests on all sorts of subranges */ 
    ret +=
        test7x8_0(fnname, fnptr, &emptyBstring, &emptyBstring, retEQ);
    ret +=
        test7x8_0(fnname, fnptr, &shortBstring, &emptyBstring, retGT);
    ret +=
        test7x8_0(fnname, fnptr, &emptyBstring, &shortBstring, retLT);
    ret +=
        test7x8_0(fnname, fnptr, &shortBstring, &shortBstring, retEQ);
    {
        bstring b = bstrcpy(&shortBstring);
        b->data[1]++;
        ret += test7x8_0(fnname, fnptr, b, &shortBstring, retGT);
        bdestroy(b);
    }  if (fnptr == biseq) {
        ret +=
            test7x8_0(fnname, fnptr, &shortBstring, &longBstring,
                    retGT);
        ret +=
            test7x8_0(fnname, fnptr, &longBstring, &shortBstring,
                    retLT);
    } else {
        ret +=
            test7x8_0(fnname, fnptr, &shortBstring, &longBstring,
                    'b' - 'T');
        ret +=
            test7x8_0(fnname, fnptr, &longBstring, &shortBstring,
                    'T' - 'b');
    }
    debug("\t# failures: %d", ret);
    return ret;
}


#define test7() test7x8 ("biseq", biseq, -1, 0, 0, 1)
#define test8() test7x8 ("bstrcmp", bstrcmp, SHRT_MIN, -1, 1, 0)
static int test9_0(const_bstring b0, const_bstring b1, int n, int res)
{
    int rv, ret = 0;
    ret += (res != (rv = bstrncmp(b0, b1, n)));
    debug(".\tbstrncmp (%s, %s, %d) = %d", dumpBstring(b0),
            dumpBstring(b1), n, rv);
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %d)", __LINE__, ret, res);
    }
    return ret;
}

static int test9(void)
{
    int ret = 0;
    debug
        ("TEST: int bstrncmp (const_bstring b0, const_bstring b1, int n);");

    /* tests with NULL */ 
    ret += test9_0(NULL, NULL, 0, SHRT_MIN);
    ret += test9_0(NULL, NULL, -1, SHRT_MIN);
    ret += test9_0(NULL, NULL, 1, SHRT_MIN);
    ret += test9_0(&emptyBstring, NULL, 0, SHRT_MIN);
    ret += test9_0(NULL, &emptyBstring, 0, SHRT_MIN);
    ret += test9_0(&emptyBstring, NULL, 1, SHRT_MIN);
    ret += test9_0(NULL, &emptyBstring, 1, SHRT_MIN);
    ret += test9_0(&badBstring1, &badBstring1, 1, SHRT_MIN);
    ret += test9_0(&badBstring2, &badBstring2, 1, SHRT_MIN);
    ret += test9_0(&emptyBstring, &badBstring1, 1, SHRT_MIN);
    ret += test9_0(&emptyBstring, &badBstring2, 1, SHRT_MIN);
    ret += test9_0(&badBstring1, &emptyBstring, 1, SHRT_MIN);
    ret += test9_0(&badBstring2, &emptyBstring, 1, SHRT_MIN);

    /* normal operation tests on all sorts of subranges */ 
    ret += test9_0(&emptyBstring, &emptyBstring, -1, 0);
    ret += test9_0(&emptyBstring, &emptyBstring, 0, 0);
    ret += test9_0(&emptyBstring, &emptyBstring, 1, 0);
    ret += test9_0(&shortBstring, &shortBstring, -1, 0);
    ret += test9_0(&shortBstring, &shortBstring, 0, 0);
    ret += test9_0(&shortBstring, &shortBstring, 1, 0);
    ret += test9_0(&shortBstring, &shortBstring, 9, 0);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test10_0(bstring b, int res, int nochange)
{
    struct tagbstring sb = bsStatic("<NULL>");
    int rv, x, ret = 0;
    if (b)
        sb = *b;
    debug(".\tbdestroy (%s) = ", dumpBstring(b));
    rv = bdestroy(b);
    debug("%d", rv);
    if (b != NULL) {
        if (rv >= 0)

            /* If the bdestroy was successful we have to assume
               the contents were "changed" */ 
            x = 1;

        else
            x = memcmp(&sb, b, sizeof sb);
    } else
        x = !nochange;
    ret += (rv != res);
    ret += (!nochange) == (!x);
    if (ret) {
        debug
            ("\t\tfailure(%d) res = %d nochange = %d, x = %d, sb.slen = %d, sb.mlen = %d, sb.data = %p",
             __LINE__, res, nochange, x, sb.slen, sb.mlen, sb.data);
    }
    return ret;
}

static int test10(void)
{
    bstring c = bstrcpy(&shortBstring);
    bstring b = bstrcpy(&emptyBstring);
    int ret = 0;
    debug("TEST: int bdestroy (const_bstring b);");

    /* tests with NULL */ 
    ret += test10_0(NULL, BSTR_ERR, 1);

    /* protected, constant and regular instantiations on empty or not */ 
    bwriteprotect(*b);
    bwriteprotect(*c);
    ret += test10_0(b, BSTR_ERR, 1);
    ret += test10_0(c, BSTR_ERR, 1);
    bwriteallow(*b);
    bwriteallow(*c);
    ret += test10_0(b, BSTR_OK, 0);
    ret += test10_0(c, BSTR_OK, 0);
    ret += test10_0(&emptyBstring, BSTR_ERR, 1);
    bwriteallow(emptyBstring);
    ret += test10_0(&emptyBstring, BSTR_ERR, 1);
    ret += test10_0(&shortBstring, BSTR_ERR, 1);
    bwriteallow(emptyBstring);
    ret += test10_0(&shortBstring, BSTR_ERR, 1);
    ret += test10_0(&badBstring1, BSTR_ERR, 1);
    ret += test10_0(&badBstring2, BSTR_ERR, 1);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test11_0(bstring s1, int pos, const_bstring s2, int res)
{
    int rv, ret = 0;
    debug(".\tbinstr (%s, %d, %s) = ", dumpBstring(s1), pos,
            dumpBstring(s2));
    rv = binstr(s1, pos, s2);
    debug("%d", rv);
    ret += (rv != res);
    if (ret) {
        debug("\t\tfailure(%d) res = %d", __LINE__, res);
    }
    return ret;
}

static int test11_1(bstring s1, int pos, const_bstring s2, int res)
{
    int rv, ret = 0;
    debug(".\tbinstrcaseless (%s, %d, %s) = ", dumpBstring(s1), pos,
            dumpBstring(s2));
    rv = binstrcaseless(s1, pos, s2);
    debug("%d", rv);
    ret += (rv != res);
    if (ret) {
        debug("\t\tfailure(%d) res = %d", __LINE__, res);
    }
    return ret;
}

static int test11(void)
{
    bstring b, c;
    int ret = 0;
    debug
        ("TEST: int binstr (const_bstring s1, int pos, const_bstring s2);");
    ret += test11_0(NULL, 0, NULL, BSTR_ERR);
    ret += test11_0(&emptyBstring, 0, NULL, BSTR_ERR);
    ret += test11_0(NULL, 0, &emptyBstring, BSTR_ERR);
    ret += test11_0(&emptyBstring, 0, &badBstring1, BSTR_ERR);
    ret += test11_0(&emptyBstring, 0, &badBstring2, BSTR_ERR);
    ret += test11_0(&badBstring1, 0, &emptyBstring, BSTR_ERR);
    ret += test11_0(&badBstring2, 0, &emptyBstring, BSTR_ERR);
    ret += test11_0(&badBstring1, 0, &badBstring2, BSTR_ERR);
    ret += test11_0(&badBstring2, 0, &badBstring1, BSTR_ERR);
    ret += test11_0(&emptyBstring, 0, &emptyBstring, 0);
    ret += test11_0(&emptyBstring, 1, &emptyBstring, BSTR_ERR);
    ret += test11_0(&shortBstring, 1, &shortBstring, BSTR_ERR);
    ret += test11_0(&shortBstring, 5, &emptyBstring, 5);
    ret += test11_0(&shortBstring, -1, &shortBstring, BSTR_ERR);
    ret += test11_0(&shortBstring, 0, &shortBstring, 0);
    ret += test11_0(&shortBstring, 0, b = bstrcpy(&shortBstring), 0);
    bdestroy(b);
    ret += test11_0(&shortBstring, 0, b =
            bfromcstr("BOGUS"), BSTR_ERR);
    bdestroy(b);
    ret += test11_0(&longBstring, 0, &shortBstring, 10);
    ret += test11_0(&longBstring, 20, &shortBstring, BSTR_ERR);
    ret += test11_0(c = bfromcstr("sssssssssap"), 0, b =
            bfromcstr("sap"), 8);
    bdestroy(c);
    bdestroy(b);
    ret += test11_0(c = bfromcstr("sssssssssap"), 3, b =
            bfromcstr("sap"), 8);
    bdestroy(c);
    bdestroy(b);
    ret += test11_0(c = bfromcstr("ssssssssssap"), 3, b =
            bfromcstr("sap"), 9);
    bdestroy(c);
    bdestroy(b);
    ret += test11_0(c = bfromcstr("sssssssssap"), 0, b =
            bfromcstr("s"), 0);
    bdestroy(c);
    bdestroy(b);
    ret += test11_0(c = bfromcstr("sssssssssap"), 3, b =
            bfromcstr("s"), 3);
    bdestroy(c);
    bdestroy(b);
    ret += test11_0(c = bfromcstr("sssssssssap"), 0, b =
            bfromcstr("a"), 9);
    bdestroy(c);
    bdestroy(b);
    ret += test11_0(c = bfromcstr("sssssssssap"), 5, b =
            bfromcstr("a"), 9);
    bdestroy(c);
    bdestroy(b);
    ret += test11_0(c = bfromcstr("sasasasasap"), 0, b =
            bfromcstr("sap"), 8);
    bdestroy(c);
    bdestroy(b);
    ret += test11_0(c = bfromcstr("ssasasasasap"), 0, b =
            bfromcstr("sap"), 9);
    bdestroy(c);
    bdestroy(b);
    debug
        ("TEST: int binstrcaseless (const_bstring s1, int pos, const_bstring s2);");
    ret += test11_1(NULL, 0, NULL, BSTR_ERR);
    ret += test11_1(&emptyBstring, 0, NULL, BSTR_ERR);
    ret += test11_1(NULL, 0, &emptyBstring, BSTR_ERR);
    ret += test11_1(&emptyBstring, 0, &badBstring1, BSTR_ERR);
    ret += test11_1(&emptyBstring, 0, &badBstring2, BSTR_ERR);
    ret += test11_1(&badBstring1, 0, &emptyBstring, BSTR_ERR);
    ret += test11_1(&badBstring2, 0, &emptyBstring, BSTR_ERR);
    ret += test11_1(&badBstring1, 0, &badBstring2, BSTR_ERR);
    ret += test11_1(&badBstring2, 0, &badBstring1, BSTR_ERR);
    ret += test11_1(&emptyBstring, 0, &emptyBstring, 0);
    ret += test11_1(&emptyBstring, 1, &emptyBstring, BSTR_ERR);
    ret += test11_1(&shortBstring, 1, &shortBstring, BSTR_ERR);
    ret += test11_1(&shortBstring, 5, &emptyBstring, 5);
    ret += test11_1(&shortBstring, -1, &shortBstring, BSTR_ERR);
    ret += test11_1(&shortBstring, 0, &shortBstring, 0);
    ret += test11_1(&shortBstring, 0, b = bstrcpy(&shortBstring), 0);
    bdestroy(b);
    ret += test11_1(&shortBstring, 0, b = bfromcstr("BOGUS"), 0);
    bdestroy(b);
    ret += test11_1(&longBstring, 0, &shortBstring, 10);
    ret += test11_1(&longBstring, 20, &shortBstring, BSTR_ERR);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test12_0(bstring s1, int pos, const_bstring s2, int res)
{
    int rv, ret = 0;
    debug(".\tbinstrr (%s, %d, %s) = ", dumpBstring(s1), pos,
            dumpBstring(s2));
    rv = binstrr(s1, pos, s2);
    debug("%d", rv);
    ret += (rv != res);
    if (ret) {
        debug("\t\tfailure(%d) res = %d", __LINE__, res);
    }
    return ret;
}

static int test12_1(bstring s1, int pos, const_bstring s2, int res)
{
    int rv, ret = 0;
    debug(".\tbinstrrcaseless (%s, %d, %s) = ", dumpBstring(s1), pos,
            dumpBstring(s2));
    rv = binstrrcaseless(s1, pos, s2);
    debug("%d", rv);
    ret += (rv != res);
    if (ret) {
        debug("\t\tfailure(%d) res = %d", __LINE__, res);
    }
    return ret;
}

static int test12(void)
{
    bstring b;
    int ret = 0;
    debug
        ("TEST: int binstrr (const_bstring s1, int pos, const_bstring s2);");
    ret += test12_0(NULL, 0, NULL, BSTR_ERR);
    ret += test12_0(&emptyBstring, 0, NULL, BSTR_ERR);
    ret += test12_0(NULL, 0, &emptyBstring, BSTR_ERR);
    ret += test12_0(&emptyBstring, 0, &badBstring1, BSTR_ERR);
    ret += test12_0(&emptyBstring, 0, &badBstring2, BSTR_ERR);
    ret += test12_0(&badBstring1, 0, &emptyBstring, BSTR_ERR);
    ret += test12_0(&badBstring2, 0, &emptyBstring, BSTR_ERR);
    ret += test12_0(&badBstring1, 0, &badBstring2, BSTR_ERR);
    ret += test12_0(&badBstring2, 0, &badBstring1, BSTR_ERR);
    ret += test12_0(&emptyBstring, 0, &emptyBstring, 0);
    ret += test12_0(&emptyBstring, 1, &emptyBstring, BSTR_ERR);
    ret += test12_0(&shortBstring, 1, &shortBstring, 0);
    ret += test12_0(&shortBstring, 5, &emptyBstring, 5);
    ret += test12_0(&shortBstring, -1, &shortBstring, BSTR_ERR);
    ret += test12_0(&shortBstring, 0, &shortBstring, 0);
    ret += test12_0(&shortBstring, 0, b = bstrcpy(&shortBstring), 0);
    bdestroy(b);
    ret += test12_0(&shortBstring, 0, b =
            bfromcstr("BOGUS"), BSTR_ERR);
    bdestroy(b);
    ret += test12_0(&longBstring, 0, &shortBstring, BSTR_ERR);
    ret += test12_0(&longBstring, 20, &shortBstring, 10);
    debug
        ("TEST: int binstrrcaseless (const_bstring s1, int pos, const_bstring s2);");
    ret += test12_1(NULL, 0, NULL, BSTR_ERR);
    ret += test12_1(&emptyBstring, 0, NULL, BSTR_ERR);
    ret += test12_1(NULL, 0, &emptyBstring, BSTR_ERR);
    ret += test12_1(&emptyBstring, 0, &badBstring1, BSTR_ERR);
    ret += test12_1(&emptyBstring, 0, &badBstring2, BSTR_ERR);
    ret += test12_1(&badBstring1, 0, &emptyBstring, BSTR_ERR);
    ret += test12_1(&badBstring2, 0, &emptyBstring, BSTR_ERR);
    ret += test12_1(&badBstring1, 0, &badBstring2, BSTR_ERR);
    ret += test12_1(&badBstring2, 0, &badBstring1, BSTR_ERR);
    ret += test12_1(&emptyBstring, 0, &emptyBstring, 0);
    ret += test12_1(&emptyBstring, 1, &emptyBstring, BSTR_ERR);
    ret += test12_1(&shortBstring, 1, &shortBstring, 0);
    ret += test12_1(&shortBstring, 5, &emptyBstring, 5);
    ret += test12_1(&shortBstring, -1, &shortBstring, BSTR_ERR);
    ret += test12_1(&shortBstring, 0, &shortBstring, 0);
    ret += test12_1(&shortBstring, 0, b = bstrcpy(&shortBstring), 0);
    bdestroy(b);
    ret += test12_1(&shortBstring, 0, b = bfromcstr("BOGUS"), 0);
    bdestroy(b);
    ret += test12_1(&longBstring, 0, &shortBstring, BSTR_ERR);
    ret += test12_1(&longBstring, 20, &shortBstring, 10);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test13_0(bstring s1, int pos, const_bstring s2, int res)
{
    int rv, ret = 0;
    debug(".\tbinchr (%s, %d, %s) = ", dumpBstring(s1), pos,
            dumpBstring(s2));
    rv = binchr(s1, pos, s2);
    debug("%d", rv);
    ret += (rv != res);
    if (ret) {
        debug("\t\tfailure(%d) res = %d", __LINE__, res);
    }
    return ret;
}

static int test13(void)
{
    bstring b;
    int ret = 0;
    struct tagbstring multipleOs = bsStatic("ooooo");
    debug
        ("TEST: int binchr (const_bstring s1, int pos, const_bstring s2);");
    ret += test13_0(NULL, 0, NULL, BSTR_ERR);
    ret += test13_0(&emptyBstring, 0, NULL, BSTR_ERR);
    ret += test13_0(NULL, 0, &emptyBstring, BSTR_ERR);
    ret += test13_0(&emptyBstring, 0, &badBstring1, BSTR_ERR);
    ret += test13_0(&emptyBstring, 0, &badBstring2, BSTR_ERR);
    ret += test13_0(&badBstring1, 0, &emptyBstring, BSTR_ERR);
    ret += test13_0(&badBstring2, 0, &emptyBstring, BSTR_ERR);
    ret += test13_0(&badBstring2, 0, &badBstring1, BSTR_ERR);
    ret += test13_0(&badBstring1, 0, &badBstring2, BSTR_ERR);
    ret += test13_0(&emptyBstring, 0, &emptyBstring, BSTR_ERR);
    ret += test13_0(&shortBstring, 0, &emptyBstring, BSTR_ERR);
    ret += test13_0(&shortBstring, 0, &shortBstring, 0);
    ret += test13_0(&shortBstring, 0, &multipleOs, 1);
    ret += test13_0(&shortBstring, 0, b = bstrcpy(&shortBstring), 0);
    bdestroy(b);
    ret += test13_0(&shortBstring, -1, &shortBstring, BSTR_ERR);
    ret += test13_0(&shortBstring, 10, &shortBstring, BSTR_ERR);
    ret += test13_0(&shortBstring, 1, &shortBstring, 1);
    ret += test13_0(&emptyBstring, 0, &shortBstring, BSTR_ERR);
    ret += test13_0(&xxxxxBstring, 0, &shortBstring, BSTR_ERR);
    ret += test13_0(&longBstring, 0, &shortBstring, 3);
    ret += test13_0(&longBstring, 10, &shortBstring, 10);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test14_0(bstring s1, int pos, const_bstring s2, int res)
{
    int rv, ret = 0;
    debug(".\tbinchrr (%s, %d, %s) = ", dumpBstring(s1), pos,
            dumpBstring(s2));
    rv = binchrr(s1, pos, s2);
    debug("%d", rv);
    ret += (rv != res);
    if (ret) {
        debug("\t\tfailure(%d) res = %d", __LINE__, res);
    }
    return ret;
}

static int test14(void)
{
    bstring b;
    int ret = 0;
    debug
        ("TEST: int binchrr (const_bstring s1, int pos, const_bstring s2);");
    ret += test14_0(NULL, 0, NULL, BSTR_ERR);
    ret += test14_0(&emptyBstring, 0, NULL, BSTR_ERR);
    ret += test14_0(NULL, 0, &emptyBstring, BSTR_ERR);
    ret += test14_0(&emptyBstring, 0, &emptyBstring, BSTR_ERR);
    ret += test14_0(&shortBstring, 0, &emptyBstring, BSTR_ERR);
    ret += test14_0(&emptyBstring, 0, &badBstring1, BSTR_ERR);
    ret += test14_0(&emptyBstring, 0, &badBstring2, BSTR_ERR);
    ret += test14_0(&badBstring1, 0, &emptyBstring, BSTR_ERR);
    ret += test14_0(&badBstring2, 0, &emptyBstring, BSTR_ERR);
    ret += test14_0(&badBstring2, 0, &badBstring1, BSTR_ERR);
    ret += test14_0(&badBstring1, 0, &badBstring2, BSTR_ERR);
    ret += test14_0(&shortBstring, 0, &shortBstring, 0);
    ret += test14_0(&shortBstring, 0, b = bstrcpy(&shortBstring), 0);
    bdestroy(b);
    ret += test14_0(&shortBstring, -1, &shortBstring, BSTR_ERR);
    ret += test14_0(&shortBstring, 5, &shortBstring, 4);
    ret += test14_0(&shortBstring, 4, &shortBstring, 4);
    ret += test14_0(&shortBstring, 1, &shortBstring, 1);
    ret += test14_0(&emptyBstring, 0, &shortBstring, BSTR_ERR);
    ret += test14_0(&xxxxxBstring, 4, &shortBstring, BSTR_ERR);
    ret += test14_0(&longBstring, 0, &shortBstring, BSTR_ERR);
    ret += test14_0(&longBstring, 10, &shortBstring, 10);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test15_0(bstring b0, int pos, const_bstring b1,
        unsigned char fill, char *res)
{
    bstring b2;
    int rv, ret = 0, linenum = 0;
    if (b0 != NULL && b0->data != NULL && b0->slen >= 0
            && b1 != NULL && b1->data != NULL && b1->slen >= 0) {
        b2 = bstrcpy(b0);
        bwriteprotect(*b2);
        debug(".\tbsetstr (%s, ", dumpBstring(b2));
        rv = bsetstr(b2, pos, b1, fill);
        ret += (rv == 0);
        if (ret && 0 == linenum)
            linenum = __LINE__;
        if (!biseq(b0, b2))
            ret++;
        if (ret && 0 == linenum)
            linenum = __LINE__;
        debug("%d, %s, %02X) = %s", pos, dumpBstring(b1), fill,
                dumpBstring(b2));
        bwriteallow(*b2);
        debug(".\tbsetstr (%s, ", dumpBstring(b2));
        rv = bsetstr(b2, pos, b1, fill);
        if (b1) {
            ret += (pos >= 0) && (b2->slen != b0->slen + b1->slen)
                && (b2->slen != pos + b1->slen);
            if (ret && 0 == linenum)
                linenum = __LINE__;
            ret += (pos < 0) && (b2->slen != b0->slen);
            if (ret && 0 == linenum)
                linenum = __LINE__;
        }
        ret += ((rv == 0) != (pos >= 0));
        if (ret && 0 == linenum)
            linenum = __LINE__;
        ret += (res == NULL);
        if (ret && 0 == linenum)
            linenum = __LINE__;
        ret += ((int)strlen(res) > b2->slen);
        if (ret && 0 == linenum)
            linenum = __LINE__;
        ret += (0 != memcmp(b2->data, res, b2->slen));
        if (ret && 0 == linenum)
            linenum = __LINE__;
        ret += b2->data[b2->slen] != '\0';
        if (ret && 0 == linenum)
            linenum = __LINE__;
        debug("%d, %s, %02X) = %s", pos, dumpBstring(b1), fill,
                dumpBstring(b2));
        bdestroy(b2);
    } else {
        ret += (BSTR_ERR != (rv = bsetstr(b0, pos, b1, fill)));
        if (ret && 0 == linenum)
            linenum = __LINE__;
        debug(".\tbsetstr (%s, %d, %s, %02X) = %d", dumpBstring(b0),
                pos, dumpBstring(b1), fill, rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", linenum, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test15(void)
{
    int ret = 0;
    debug
        ("TEST: int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill);");

    /* tests with NULL */ 
    ret += test15_0(NULL, 0, NULL, (unsigned char)'?', NULL);
    ret += test15_0(NULL, 0, &emptyBstring, (unsigned char)'?', NULL);
    ret += test15_0(&badBstring1, 0, NULL, (unsigned char)'?', NULL);
    ret +=
        test15_0(&badBstring1, 0, &badBstring1, (unsigned char)'?',
                NULL);
    ret +=
        test15_0(&emptyBstring, 0, &badBstring1, (unsigned char)'?',
                NULL);
    ret +=
        test15_0(&badBstring1, 0, &emptyBstring, (unsigned char)'?',
                NULL);
    ret += test15_0(&badBstring2, 0, NULL, (unsigned char)'?', NULL);
    ret +=
        test15_0(&badBstring2, 0, &badBstring2, (unsigned char)'?',
                NULL);
    ret +=
        test15_0(&emptyBstring, 0, &badBstring2, (unsigned char)'?',
                NULL);
    ret +=
        test15_0(&badBstring2, 0, &emptyBstring, (unsigned char)'?',
                NULL);

    /* normal operation tests */ 
    ret +=
        test15_0(&emptyBstring, 0, &emptyBstring, (unsigned char)'?',
                "");
    ret +=
        test15_0(&emptyBstring, 5, &emptyBstring, (unsigned char)'?',
                "?????");
    ret +=
        test15_0(&emptyBstring, 5, &shortBstring, (unsigned char)'?',
                "?????bogus");
    ret +=
        test15_0(&shortBstring, 0, &emptyBstring, (unsigned char)'?',
                "bogus");
    ret +=
        test15_0(&emptyBstring, 0, &shortBstring, (unsigned char)'?',
                "bogus");
    ret +=
        test15_0(&shortBstring, 0, &shortBstring, (unsigned char)'?',
                "bogus");
    ret +=
        test15_0(&shortBstring, -1, &shortBstring, (unsigned char)'?',
                "bogus");
    ret +=
        test15_0(&shortBstring, 2, &shortBstring, (unsigned char)'?',
                "bobogus");
    ret +=
        test15_0(&shortBstring, 6, &shortBstring, (unsigned char)'?',
                "bogus?bogus");
    ret +=
        test15_0(&shortBstring, 6, NULL, (unsigned char)'?', "bogus?");
    debug("\t# failures: %d", ret);
    return ret;
}

static int test16_0(bstring b0, int pos, const_bstring b1,
        unsigned char fill, char *res)
{
    bstring b2;
    int rv, ret = 0;
    if (b0 != NULL && b0->data != NULL && b0->slen >= 0
            && b1 != NULL && b1->data != NULL && b1->slen >= 0) {
        b2 = bstrcpy(b0);
        bwriteprotect(*b2);
        debug(".\tbinsert (%s, ", dumpBstring(b2));
        rv = binsert(b2, pos, b1, fill);
        ret += (rv == 0);
        if (!biseq(b0, b2))
            ret++;
        debug("%d, %s, %02X) = %s", pos, dumpBstring(b1), fill,
                dumpBstring(b2));
        bwriteallow(*b2);
        debug(".\tbinsert (%s, ", dumpBstring(b2));
        rv = binsert(b2, pos, b1, fill);
        if (b1) {
            ret += (pos >= 0) && (b2->slen != b0->slen + b1->slen)
                && (b2->slen != pos + b1->slen);
            ret += (pos < 0) && (b2->slen != b0->slen);
            ret += ((rv == 0) != (pos >= 0 && pos <= b2->slen));
        }
        ret += (res == NULL) || ((int)strlen(res) > b2->slen) 
            ||(0 != memcmp(b2->data, res, b2->slen));
        ret += b2->data[b2->slen] != '\0';
        debug("%d, %s, %02X) = %s", pos, dumpBstring(b1), fill,
                dumpBstring(b2));
        bdestroy(b2);
    } else {
        ret += (BSTR_ERR != (rv = binsert(b0, pos, b1, fill)));
        debug(".\tbinsert (%s, %d, %s, %02X) = %d", dumpBstring(b0),
                pos, dumpBstring(b1), fill, rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test16(void)
{
    int ret = 0;
    debug
        ("TEST: int binsert (bstring b0, int pos, const_bstring b1, unsigned char fill);");

    /* tests with NULL */ 
    ret += test16_0(NULL, 0, NULL, (unsigned char)'?', NULL);
    ret += test16_0(NULL, 0, &emptyBstring, (unsigned char)'?', NULL);
    ret += test16_0(&badBstring1, 0, NULL, (unsigned char)'?', NULL);
    ret +=
        test16_0(&badBstring1, 0, &badBstring1, (unsigned char)'?',
                NULL);
    ret +=
        test16_0(&emptyBstring, 0, &badBstring1, (unsigned char)'?',
                NULL);
    ret +=
        test16_0(&badBstring1, 0, &emptyBstring, (unsigned char)'?',
                NULL);
    ret += test16_0(&badBstring2, 0, NULL, (unsigned char)'?', NULL);
    ret +=
        test16_0(&badBstring2, 0, &badBstring2, (unsigned char)'?',
                NULL);
    ret +=
        test16_0(&emptyBstring, 0, &badBstring2, (unsigned char)'?',
                NULL);
    ret +=
        test16_0(&badBstring2, 0, &emptyBstring, (unsigned char)'?',
                NULL);

    /* normal operation tests */ 
    ret +=
        test16_0(&emptyBstring, 0, &emptyBstring, (unsigned char)'?',
                "");
    ret +=
        test16_0(&emptyBstring, 5, &emptyBstring, (unsigned char)'?',
                "?????");
    ret +=
        test16_0(&emptyBstring, 5, &shortBstring, (unsigned char)'?',
                "?????bogus");
    ret +=
        test16_0(&shortBstring, 0, &emptyBstring, (unsigned char)'?',
                "bogus");
    ret +=
        test16_0(&emptyBstring, 0, &shortBstring, (unsigned char)'?',
                "bogus");
    ret +=
        test16_0(&shortBstring, 0, &shortBstring, (unsigned char)'?',
                "bogusbogus");
    ret +=
        test16_0(&shortBstring, -1, &shortBstring, (unsigned char)'?',
                "bogus");
    ret +=
        test16_0(&shortBstring, 2, &shortBstring, (unsigned char)'?',
                "bobogusgus");
    ret +=
        test16_0(&shortBstring, 6, &shortBstring, (unsigned char)'?',
                "bogus?bogus");
    ret +=
        test16_0(&shortBstring, 6, NULL, (unsigned char)'?', "bogus");
    debug("\t# failures: %d", ret);
    return ret;
}

static int test17_0(bstring s1, int pos, int len, char *res)
{
    bstring b2;
    int rv, ret = 0;
    if (s1 != NULL && s1->data != NULL && s1->slen >= 0) {
        b2 = bstrcpy(s1);
        bwriteprotect(*b2);
        debug(".\tbdelete (%s, ", dumpBstring(b2));
        rv = bdelete(b2, pos, len);
        ret += (rv == 0);
        if (!biseq(s1, b2))
            ret++;
        debug("%d, %d) = %s", pos, len, dumpBstring(b2));
        bwriteallow(*b2);
        debug(".\tbdelete (%s, ", dumpBstring(b2));
        rv = bdelete(b2, pos, len);
        ret += (len >= 0) != (rv == 0);
        ret += (b2->slen > s1->slen) || (b2->slen < pos
                && s1->slen >= pos);
        ret += (res == NULL)
            || ((int)strlen(res) > b2->slen)  ||(0 !=
                    memcmp(b2->data, res,
                        b2->slen));
        ret += b2->data[b2->slen] != '\0';
        debug("%d, %d) = %s", pos, len, dumpBstring(b2));
        bdestroy(b2);
    } else {
        ret += (BSTR_ERR != (rv = bdelete(s1, pos, len)));
        debug(".\tbdelete (%s, %d, %d) = %d", dumpBstring(s1), pos,
                len, rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test17(void)
{
    int ret = 0;
    debug("TEST: int bdelete (bstring s1, int pos, int len);");

    /* tests with NULL */ 
    ret += test17_0(NULL, 0, 0, NULL);
    ret += test17_0(&badBstring1, 0, 0, NULL);
    ret += test17_0(&badBstring2, 0, 0, NULL);

    /* normal operation tests */ 
    ret += test17_0(&emptyBstring, 0, 0, "");
    ret += test17_0(&shortBstring, 1, 3, "bs");
    ret += test17_0(&shortBstring, -1, 3, "gus");
    ret += test17_0(&shortBstring, 1, -3, "bogus");
    ret += test17_0(&shortBstring, 3, 9, "bog");
    ret += test17_0(&shortBstring, 3, 1, "bogs");
    ret += test17_0(&longBstring, 4, 300, "This");
    debug("\t# failures: %d", ret);
    return ret;
}

static int test18_0(bstring b, int len, int res, int mlen)
{
    int ret = 0;
    int rv;
    int ol = 0;
    debug(".\tballoc (%s, %d) = ", dumpBstring(b), len);
    if (b)
        ol = b->mlen;
    rv = balloc(b, len);
    debug("%d", rv);
    if (b != NULL && b->data != NULL && b->slen >= 0 && ol > b->mlen) {
        debug("\t\tfailure(%d) oldmlen = %d, newmlen %d", __LINE__, ol,
                b->mlen);
        ret++;
    }
    if (rv != res) {
        debug("\t\tfailure(%d) res = %d", __LINE__, res);
        ret++;
    }
    if (b != NULL && (mlen > b->mlen || b->mlen == 0)) {
        debug("\t\tfailure(%d) b->mlen = %d mlen = %d", __LINE__,
                b->mlen, mlen);
        ret++;
    }
    return ret;
}

static int test18_1_int(bstring b, int len, int res, int mlen,
        int __line__)
{
    int ret = 0;
    int rv;
    int ol = 0;
    debug(".\tballocmin (%s, %d) = ", dumpBstring(b), len);
    if (b)
        ol = b->mlen;
    rv = ballocmin(b, len);
    debug("[%d] %d", __LINE__, rv);
    if (b != NULL && b->data != NULL && b->mlen != mlen) {
        debug
            ("\t\t[%d] failure(%d) oldmlen = %d, newmlen = %d, mlen = %d len = %d",
             __line__, __LINE__, ol, b->mlen, mlen, b->slen);
        ret++;
    }
    if (rv != res) {
        debug("\t\t[%d] failure(%d) res = %d", __line__, __LINE__,
                res);
        ret++;
    }
    return ret;
}


#define test18_1(b, len, res, mlen) test18_1_int (b, len, res, mlen, __LINE__)
static int test18(void)
{
    int ret = 0, reto;
    bstring b = bfromcstr("test");
    debug("TEST: int balloc (bstring s, int len);");

    /* tests with NULL */ 
    ret += test18_0(NULL, 2, BSTR_ERR, 0);
    ret += test18_0(&badBstring1, 2, BSTR_ERR, 0);
    ret += test18_0(&badBstring2, 2, BSTR_ERR, 0);

    /* normal operation tests */ 
    ret += test18_0(b, 2, 0, b->mlen);
    ret += test18_0(b, -1, BSTR_ERR, b->mlen);
    ret += test18_0(b, 9, 0, 9);
    ret += test18_0(b, 2, 0, 9);
    bwriteprotect(*b);
    ret += test18_0(b, 4, BSTR_ERR, b->mlen);
    bwriteallow(*b);
    ret += test18_0(b, 2, 0, b->mlen);
    ret += test18_0(&emptyBstring, 9, BSTR_ERR, emptyBstring.mlen);
    bdestroy(b);
    debug("\t# failures: %d", ret);
    reto = ret;
    ret = 0;
    b = bfromcstr("test");
    debug("TEST: int ballocmin (bstring s, int len);");

    /* tests with NULL */ 
    ret += test18_1(NULL, 2, BSTR_ERR, 0);
    ret += test18_1(&badBstring1, 2, BSTR_ERR, 0);
    ret += test18_1(&badBstring2, 2, BSTR_ERR, 2);

    /* normal operation tests */ 
    ret += test18_1(b, 2, 0, b->slen + 1);
    ret += test18_1(b, -1, BSTR_ERR, b->mlen);
    ret += test18_1(b, 9, 0, 9);
    ret += test18_1(b, 2, 0, b->slen + 1);
    ret += test18_1(b, 9, 0, 9);
    bwriteprotect(*b);
    ret += test18_1(b, 4, BSTR_ERR, -1);
    bwriteallow(*b);
    ret += test18_1(b, 2, 0, b->slen + 1);
    ret += test18_1(&emptyBstring, 9, BSTR_ERR, emptyBstring.mlen);
    bdestroy(b);
    debug("\t# failures: %d", ret);
    return reto + ret;
}

static int test19_0(bstring b, int len, const char *res, int erv)
{
    int rv, ret = 0;
    bstring b1;
    if (b != NULL && b->data != NULL && b->slen >= 0) {
        b1 = bstrcpy(b);
        bwriteprotect(*b1);
        ret += bpattern(b1, len) != BSTR_ERR;
        ret += !biseq(b1, b);
        bwriteallow(*b1);
        debug(".\tbpattern (%s, %d) = ", dumpBstring(b1), len);
        rv = bpattern(b1, len);
        debug("%s", dumpBstring(b1));
        ret += (rv != erv);
        ret += (res == NULL) || ((int)strlen(res) > b1->slen) 
            ||(0 != memcmp(b1->data, res, b1->slen));
        ret += b1->data[b1->slen] != '\0';
        bdestroy(b1);
    } else {
        ret += BSTR_ERR != (rv = bpattern(b, len));
        debug(".\tbpattern (%s, %d) = %d", dumpBstring(b), len, rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) rv = %d erv = %d (res = %p", __LINE__,
                rv, erv, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test19(void)
{
    int ret = 0;
    debug("TEST: int bpattern (bstring b, int len);");

    /* tests with NULL */ 
    ret += test19_0(NULL, 0, NULL, BSTR_ERR);
    ret += test19_0(NULL, 5, NULL, BSTR_ERR);
    ret += test19_0(NULL, -5, NULL, BSTR_ERR);
    ret += test19_0(&badBstring1, 5, NULL, BSTR_ERR);
    ret += test19_0(&badBstring2, 5, NULL, BSTR_ERR);

    /* normal operation tests */ 
    ret += test19_0(&emptyBstring, 0, "", BSTR_ERR);
    ret += test19_0(&emptyBstring, 10, "", BSTR_ERR);
    ret += test19_0(&emptyBstring, -1, "", BSTR_ERR);
    ret += test19_0(&shortBstring, 0, "", 0);
    ret += test19_0(&shortBstring, 12, "bogusbogusbo", 0);
    ret += test19_0(&shortBstring, -1, "bogus", BSTR_ERR);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test20(void)
{
    int ret = 0;

#if !defined (BSTRLIB_NOVSNP)
    int rv;
    bstring b, c;
    debug("TEST: bstring bformat (const char * fmt, ...);");

    /* tests with NULL */ 
    debug(".\tbformat (NULL, 1, 2) = ");
    b = bformat(NULL, 1, 2);
    debug("%s", dumpBstring(b));
    ret += b != NULL;

    /* normal operation tests */ 
    debug(".\tbformat (\"%%d %%s\", 1, \"xy\") = ");
    b = bformat("%d %s", 1, "xy");
    debug("%s", dumpBstring(b));
    ret += !biseq(c = bfromcstr("1 xy"), b);
    bdestroy(b);
    debug(".\tbformat (\"%%d %%s(%%s)\", 6, %s, %s) = ",
            dumpBstring(c), dumpBstring(&shortBstring));
    b = bformat("%d %s(%s)", 6, c->data, shortBstring.data);
    debug("%s", dumpBstring(b));
    bdestroy(c);
    ret += !biseq(c = bfromcstr("6 1 xy(bogus)"), b);
    bdestroy(c);
    bdestroy(b);
    debug(".\tbformat (\"%%s%%s%%s%%s%%s%%s%%s%%s\", ...) ...");
    b = bformat("%s%s%s%s%s%s%s%s", longBstring.data,
            longBstring.data , longBstring.data,
            longBstring.data , longBstring.data,
            longBstring.data , longBstring.data,
            longBstring.data);
    c = bstrcpy(&longBstring);
    bconcat(c, c);
    bconcat(c, c);
    bconcat(c, c);
    ret += !biseq(c, b);
    bdestroy(c);
    bdestroy(b);
    debug("\t# failures: %d", ret);
    b = bfromcstr("");
    debug("TEST: int bformata (bstring b, const char * fmt, ...);");

    /* tests with NULL */ 
    debug(".\tbformata (%s, NULL, 1, 2) = ", dumpBstring(b));
    rv = bformata(b, NULL, 1, 2);
    debug("%d", rv);
    ret += rv != BSTR_ERR;
    debug(".\tbformata (%s, \"%%d %%d\", 1, 2) = ",
            dumpBstring(&badBstring1));
    rv = bformata(&badBstring1, "%d %d", 1, 2);
    debug("%d", rv);
    ret += rv != BSTR_ERR;
    debug(".\tbformata (%s, \"%%d %%d\", 1, 2) = ", dumpBstring(b));
    rv = bformata(b, "%d %d", 1, 2);
    debug("%s", dumpBstring(b));
    ret += !biseq(c = bfromcstr("1 2"), b);
    bdestroy(c);
    bdestroy(b);
    debug
        (".\tbformata (\"x\", \"%%s%%s%%s%%s%%s%%s%%s%%s\", ...) ...");
    rv = bformata(b =
            bfromcstr("x"), "%s%s%s%s%s%s%s%s",
            longBstring.data, longBstring.data,
            longBstring.data, longBstring.data,
            longBstring.data, longBstring.data,
            longBstring.data, longBstring.data);
    ret += rv == BSTR_ERR;
    c = bstrcpy(&longBstring);
    bconcat(c, c);
    bconcat(c, c);
    bconcat(c, c);
    binsertch(c, 0, 1, (char)'x');
    ret += !biseq(c, b);
    bdestroy(c);
    bdestroy(b);
    debug("\t# failures: %d", ret);
    b = bfromcstr("Initial");
    debug
        ("TEST: int bassignformat (bstring b, const char * fmt, ...);");

    /* tests with NULL */ 
    debug(".\tbassignformat (%s, NULL, 1, 2) = ", dumpBstring(b));
    rv = bassignformat(b, NULL, 1, 2);
    debug("%d", rv);
    ret += rv != BSTR_ERR;
    debug(".\tbassignformat (%s, \"%%d %%d\", 1, 2) = ",
            dumpBstring(&badBstring1));
    rv = bassignformat(&badBstring1, "%d %d", 1, 2);
    debug("%d", rv);
    ret += rv != BSTR_ERR;
    debug(".\tbassignformat (%s, \"%%d %%d\", 1, 2) = ",
            dumpBstring(b));
    rv = bassignformat(b, "%d %d", 1, 2);
    debug("%s", dumpBstring(b));
    ret += !biseq(c = bfromcstr("1 2"), b);
    bdestroy(c);
    bdestroy(b);
    debug
        (".\tbassignformat (\"x\", \"%%s%%s%%s%%s%%s%%s%%s%%s\", ...) ...");
    rv = bassignformat(b =
            bfromcstr("x"), "%s%s%s%s%s%s%s%s",
            longBstring.data, longBstring.data,
            longBstring.data, longBstring.data,
            longBstring.data, longBstring.data,
            longBstring.data, longBstring.data);
    ret += rv == BSTR_ERR;
    c = bstrcpy(&longBstring);
    bconcat(c, c);
    bconcat(c, c);
    bconcat(c, c);
    ret += !biseq(c, b);
    bdestroy(c);
    bdestroy(b);
    debug("\t# failures: %d", ret);

#endif	/*  */
    return ret;
}

static int test21_0(bstring b, char sc, int ns)
{
    struct bstrList *l;
    int ret = 0;
    debug(".\tbsplit (%s, '%c') = ", dumpBstring(b), sc);
    if (b != NULL && b->data != NULL && b->slen >= 0) {
        bstring c;
        struct tagbstring t;
        blk2tbstr(t, &sc, 1);
        debug("{");
        l = bsplit(b, sc);
        if (l) {
            int i;
            for (i = 0; i < l->qty; i++) {
                if (i != 0)
                    debug(", ");
                debug("%s", dumpBstring(l->entry[i]));
            }
            debug(":<%d>", l->qty);
            if (ns != l->qty)
                ret++;
        } else {
            debug("NULL");
            ret++;
        }
        debug("}");
        c = bjoin(l, &t);
        ret += !biseq(c, b);
        bdestroy(c);
        ret += 0 != bstrListDestroy(l);
    } else {
        l = bsplit(b, sc);
        ret += (l != NULL);
        debug("%p", (void *)l);
    }  if (ret) {
        debug("\t\tfailure(%d) ns = %d", __LINE__, ns);
    }
    return ret;
}

static int test21_1(bstring b, const_bstring sc, int ns)
{
    struct bstrList *l;
    int ret = 0;
    debug(".\tbsplitstr (%s, %s) = ", dumpBstring(b),
            dumpBstring(sc));
    if (b != NULL && b->data != NULL && b->slen >= 0) {
        bstring c;
        debug("{");
        l = bsplitstr(b, sc);
        if (l) {
            int i;
            for (i = 0; i < l->qty; i++) {
                if (i != 0)
                    debug(", ");
                debug("%s", dumpBstring(l->entry[i]));
            }
            debug(":<%d>", l->qty);
            if (ns != l->qty)
                ret++;
        } else {
            debug("NULL");
            ret++;
        }
        debug("}");
        c = bjoin(l, sc);
        ret += !biseq(c, b);
        bdestroy(c);
        ret += 0 != bstrListDestroy(l);
    } else {
        l = bsplitstr(b, sc);
        ret += (l != NULL);
        debug("%p", (void *)l);
    }  if (ret) {
        debug("\t\tfailure(%d) ns = %d", __LINE__, ns);
    }
    return ret;
}

static int test21(void)
{
    struct tagbstring is = bsStatic("is");
    struct tagbstring ng = bsStatic("ng");
    int ret = 0;
    debug
        ("TEST: struct bstrList * bsplit (const_bstring str, unsigned char splitChar);");

    /* tests with NULL */ 
    ret += test21_0(NULL, (char)'?', 0);
    ret += test21_0(&badBstring1, (char)'?', 0);
    ret += test21_0(&badBstring2, (char)'?', 0);

    /* normal operation tests */ 
    ret += test21_0(&emptyBstring, (char)'?', 1);
    ret += test21_0(&shortBstring, (char)'o', 2);
    ret += test21_0(&shortBstring, (char)'s', 2);
    ret += test21_0(&shortBstring, (char)'b', 2);
    ret += test21_0(&longBstring, (char)'o', 9);
    debug
        ("TEST: struct bstrList * bsplitstr (bstring str, const_bstring splitStr);");
    ret += test21_1(NULL, NULL, 0);
    ret += test21_1(&badBstring1, &emptyBstring, 0);
    ret += test21_1(&badBstring2, &emptyBstring, 0);

    /* normal operation tests */ 
    ret += test21_1(&shortBstring, &emptyBstring, 5);
    ret += test21_1(&longBstring, &is, 3);
    ret += test21_1(&longBstring, &ng, 5);
    if (0 == ret) {
        struct bstrList *l;
        unsigned char c;
        struct tagbstring t;
        bstring b;
        bstring list[3] = {
            &emptyBstring, &shortBstring, &longBstring};
        int i;
        blk2tbstr(t, &c, 1);
        for (i = 0; i < 3; i++) {
            c = (unsigned char)'\0';
            for (;;) {
                b = bjoin(l = bsplit(list[i], c), &t);
                if (!biseq(b, list[i])) {
                    debug("\t\tfailure(%d) ", __LINE__);
                    debug("join (bsplit (%s, x%02X), {x%02X}) = %s",
                            dumpBstring(list[i]), c, c, dumpBstring(b));
                    ret++;
                }
                bdestroy(b);
                bstrListDestroy(l);
                if (ret)
                    break;
                b = bjoin(l = bsplitstr(list[i], &t), &t);
                if (!biseq(b, list[i])) {
                    debug("\t\tfailure(%d) ", __LINE__);
                    debug
                        ("join (bsplitstr (%s, {x%02X}), {x%02X}) = %s",
                         dumpBstring(list[i]), c, c, dumpBstring(b));
                    ret++;
                }
                bdestroy(b);
                bstrListDestroy(l);
                if (ret)
                    break;
                if (UCHAR_MAX == c)
                    break;
                c++;
            }
            if (ret)
                break;
        }
    }
    debug("\t# failures: %d", ret);
    return ret;
}

static int test22_0(const_bstring b, const_bstring sep, int ns, ...)
{
    va_list arglist;
    struct bstrList *l;
    int ret = 0;
    debug(".\tbsplits (%s, %s)", dumpBstring(b), dumpBstring(sep));
    if (b != NULL && b->data != NULL && b->slen >= 0 && sep != NULL
            && sep->data != NULL && sep->slen >= 0) {
        debug(" {");
        l = bsplits(b, sep);
        if (l) {
            int i;
            va_start(arglist, ns);
            for (i = 0; i < l->qty; i++) {
                char *res;
                res = va_arg(arglist, char *);
                if (i != 0)
                    debug(", ");
                debug("%s", dumpBstring(l->entry[i]));
                ret += (res == NULL)
                    || ((int)strlen(res) > l->entry[i]->slen)  ||(0 !=
                            memcmp
                            (l->
                             entry
                             [i]->
                             data,
                             res,
                             l->
                             entry
                             [i]->
                             slen));
                ret += l->entry[i]->data[l->entry[i]->slen] != '\0';
            }  va_end(arglist);
            debug(":<%d>", l->qty);
            if (ns != l->qty)
                ret++;
        } else {
            debug("NULL");
            ret += (ns != 0);
        }
        debug("}");
        ret += (0 != bstrListDestroy(l) && l != NULL);
    } else {
        l = bsplits(b, sep);
        ret += (l != NULL);
        debug(" = %p", (void *)l);
    }  if (ret) {
        debug("\t\tfailure(%d) ns = %d", __LINE__, ns);
    }
    return ret;
}

static int test22(void)
{
    int ret = 0;
    struct tagbstring o = bsStatic("o");
    struct tagbstring s = bsStatic("s");
    struct tagbstring b = bsStatic("b");
    struct tagbstring bs = bsStatic("bs");
    struct tagbstring uo = bsStatic("uo");
    debug
        ("TEST: extern struct bstrList * bsplits (const_bstring str, const_bstring splitStr);");

    /* tests with NULL */ 
    ret += test22_0(NULL, &o, 0);
    ret += test22_0(&o, NULL, 0);

    /* normal operation tests */ 
    ret += test22_0(&emptyBstring, &o, 1, "");
    ret += test22_0(&emptyBstring, &uo, 1, "");
    ret += test22_0(&shortBstring, &emptyBstring, 1, "bogus");
    ret += test22_0(&shortBstring, &o, 2, "b", "gus");
    ret += test22_0(&shortBstring, &s, 2, "bogu", "");
    ret += test22_0(&shortBstring, &b, 2, "", "ogus");
    ret += test22_0(&shortBstring, &bs, 3, "", "ogu", "");
    ret +=
        test22_0(&longBstring, &o, 9, "This is a b", "gus but reas",
                "nably l", "ng string.  Just l", "ng en", "ugh t",
                " cause s", "me mall", "cing.");
    ret += test22_0(&shortBstring, &uo, 3, "b", "g", "s");
    if (0 == ret) {
        struct bstrList *l;
        unsigned char c;
        struct tagbstring t;
        bstring bb;
        bstring list[3] = {
            &emptyBstring, &shortBstring, &longBstring};
        int i;
        blk2tbstr(t, &c, 1);
        for (i = 0; i < 3; i++) {
            c = (unsigned char)'\0';
            for (;;) {
                bb = bjoin(l = bsplits(list[i], &t), &t);
                if (!biseq(bb, list[i])) {
                    debug("\t\tfailure(%d) ", __LINE__);
                    debug("join (bsplits (%s, {x%02X}), {x%02X}) = %s",
                            dumpBstring(list[i]), c, c, dumpBstring(bb));
                    ret++;
                }
                bdestroy(bb);
                bstrListDestroy(l);
                if (ret)
                    break;
                if (UCHAR_MAX == c)
                    break;
                c++;
            }
            if (ret)
                break;
        }
    }
    debug("\t# failures: %d", ret);
    return ret;
}

struct sbstr {
    int ofs;
    bstring b;
};
static size_t test23_aux_read(void *buff, size_t elsize,
        size_t nelem, void *parm)
{
    struct sbstr *sb = (struct sbstr *)parm;
    int els, len;
    if (parm == NULL || elsize == 0 || nelem == 0)
        return 0;
    len = (int)(nelem * elsize);
    if (len <= 0)
        return 0;
    if (len + sb->ofs > sb->b->slen)
        len = sb->b->slen - sb->ofs;
    els = (int)(len / elsize);
    len = (int)(els * elsize);
    if (len > 0) {
        memcpy(buff, sb->b->data + sb->ofs, len);
        sb->ofs += len;
    }
    return els;
}

static int test23_aux_open(struct sbstr *sb, bstring b)
{
    if (!sb || b == NULL || b->data == NULL)
        return -__LINE__;
    sb->ofs = 0;
    sb->b = b;
    return 0;
}

static int test23_aux_splitcb(void *parm, int ofs,
        const struct tagbstring *entry)
{
    bstring b = (bstring) parm;
    ofs = ofs;
    if (b->slen > 0)
        bconchar(b, (char)'|');
    bconcat(b, entry);
    return 0;
}

struct tagBss {
    int first;
    unsigned char sc;
    bstring b;
};
static int test23_aux_splitcbx(void *parm, int ofs,
        const struct tagbstring *entry)
{
    struct tagBss *p = (struct tagBss *)parm;
    ofs = ofs;
    if (!p->first) {
        bconchar(p->b, (char)p->sc);
    } else
        p->first = 0;
    bconcat(p->b, entry);
    return 0;
}

static int test23(void)
{
    struct tagbstring space = bsStatic(" ");
    struct sbstr sb;
    struct bStream *bs;
    bstring b;
    int l, ret = 0;
    debug("TEST: bstream integrated test");
    test23_aux_open(&sb, &longBstring);
    ret += NULL != (bs = bsopen((bNread) NULL, &sb));
    ret += NULL == (bs = bsopen((bNread) test23_aux_read, &sb));
    ret += (bseof(bs) != 0);
    ret += BSTR_ERR != bsbufflength(NULL, -1);
    ret += BSTR_ERR != bsbufflength(NULL, 1);
    ret += BSTR_ERR != bsbufflength(bs, -1);
    debug(".\tbsbufflength (bs, 0) -> %d", bsbufflength(bs, 0));
    ret += BSTR_ERR == bsbufflength(bs, 1);
    ret += BSTR_ERR != bspeek(NULL, bs);
    ret += BSTR_ERR != bsreadln(NULL, bs, (char)'?');
    ret += BSTR_ERR != bsreadln(&emptyBstring, bs, (char)'?');
    ret += BSTR_ERR != bspeek(&emptyBstring, bs);
    ret += BSTR_ERR == bspeek(b = bfromcstr(""), bs);
    debug(".\tbspeek () -> %s", dumpBstring(b));
    ret += BSTR_ERR != bsreadln(b, NULL, (char)'?');
    b->slen = 0;
    ret += BSTR_ERR == bsreadln(b, bs, (char)'?');
    ret += (bseof(bs) <= 0);
    ret += biseq(b, &longBstring) < 0;
    debug(".\tbsreadln ('?') -> %s", dumpBstring(b));
    ret += BSTR_ERR == bsunread(bs, b);
    ret += (bseof(bs) != 0);
    debug(".\tbsunread (%s)", dumpBstring(b));
    b->slen = 0;
    ret += BSTR_ERR == bspeek(b, bs);
    ret += biseq(b, &longBstring) < 0;
    debug(".\tbspeek () -> %s", dumpBstring(b));
    b->slen = 0;
    ret += BSTR_ERR == bsreadln(b, bs, (char)'?');
    ret += (bseof(bs) <= 0);
    ret += biseq(b, &longBstring) < 0;
    debug(".\tbsreadln ('?') -> %s", dumpBstring(b));
    ret += NULL == bsclose(bs);
    sb.ofs = 0;
    ret += NULL == (bs = bsopen((bNread) test23_aux_read, &sb));
    b->slen = 0;
    ret += BSTR_ERR == bsreadln(b, bs, (char)'.');
    l = b->slen;
    ret += (0 != bstrncmp(b, &longBstring, l))
        || (longBstring.data[l - 1] != '.');
    debug(".\tbsreadln ('.') -> %s", dumpBstring(b));
    ret += BSTR_ERR == bsunread(bs, b);
    debug(".\tbsunread (%s)", dumpBstring(b));
    b->slen = 0;
    ret += BSTR_ERR == bspeek(b, bs);
    ret += biseq(b, &longBstring) < 0;
    debug(".\tbspeek () -> %s", dumpBstring(b));
    b->slen = 0;
    ret += BSTR_ERR == bsreadln(b, bs, (char)'.');
    ret += b->slen != l || (0 != bstrncmp(b, &longBstring, l))
        || (longBstring.data[l - 1] != '.');
    debug(".\tbsreadln ('.') -> %s", dumpBstring(b));
    ret += NULL == bsclose(bs);
    test23_aux_open(&sb, &longBstring);
    ret += NULL == (bs = bsopen((bNread) test23_aux_read, &sb));
    ret += (bseof(bs) != 0);
    b->slen = 0;
    l = bssplitscb(bs, &space, test23_aux_splitcb, b);
    ret += (bseof(bs) <= 0);
    ret += NULL == bsclose(bs);
    debug(".\tbssplitscb (' ') -> %s", dumpBstring(b));
    for (l = 1; l < 4; l++) {
        char *str;
        for (str = (char *)longBstring.data; *str; str++) {
            test23_aux_open(&sb, &longBstring);
            ret += NULL == (bs =
                    bsopen((bNread) test23_aux_read, &sb));
            ret += bseof(bs) != 0;
            ret += 0 > bsbufflength(bs, l);
            b->slen = 0;
            while (0 == bsreadlna(b, bs, *str)) ;
            ret += 0 == biseq(b, &longBstring);
            ret += bseof(bs) <= 0;
            ret += NULL == bsclose(bs);
            if (ret)
                break;
        }
        if (ret)
            break;
    }
    bdestroy(b);
    if (0 == ret) {
        unsigned char c;
        struct tagbstring t;
        bstring list[3] = {
            &emptyBstring, &shortBstring, &longBstring};
        int i;
        blk2tbstr(t, &c, 1);
        for (i = 0; i < 3; i++) {
            c = (unsigned char)'\0';
            for (;;) {
                struct tagBss bss;
                bss.sc = c;
                bss.b = bfromcstr("");
                bss.first = 1;
                test23_aux_open(&sb, list[i]);
                bs = bsopen((bNread) test23_aux_read, &sb);
                bssplitscb(bs, &t, test23_aux_splitcbx, &bss);
                bsclose(bs);
                if (!biseq(bss.b, list[i])) {
                    debug("\t\tfailure(%d) ", __LINE__);
                    debug
                        ("join (bssplitscb (%s, {x%02X}), {x%02X}) = %s",
                         dumpBstring(list[i]), c, c,
                         dumpBstring(bss.b));
                    ret++;
                }
                bdestroy(bss.b);
                if (ret)
                    break;
                if (UCHAR_MAX == c)
                    break;
                c++;
            }
            if (ret)
                break;
            for (;;) {
                struct tagBss bss;
                bss.sc = c;
                bss.b = bfromcstr("");
                bss.first = 1;
                test23_aux_open(&sb, list[i]);
                bs = bsopen((bNread) test23_aux_read, &sb);
                bssplitstrcb(bs, &t, test23_aux_splitcbx, &bss);
                bsclose(bs);
                if (!biseq(bss.b, list[i])) {
                    debug("\t\tfailure(%d) ", __LINE__);
                    debug
                        ("join (bssplitstrcb (%s, {x%02X}), {x%02X}) = %s",
                         dumpBstring(list[i]), c, c,
                         dumpBstring(bss.b));
                    ret++;
                }
                bdestroy(bss.b);
                if (ret)
                    break;
                if (UCHAR_MAX == c)
                    break;
                c++;
            }
            if (ret)
                break;
        }
    }
    debug("\t# failures: %d", ret);
    return ret;
}

static int test24_0(bstring s1, int pos, const_bstring s2, int res)
{
    int rv, ret = 0;
    debug(".\tbninchr (%s, %d, %s) = ", dumpBstring(s1), pos,
            dumpBstring(s2));
    rv = bninchr(s1, pos, s2);
    debug("%d", rv);
    ret += (rv != res);
    if (ret) {
        debug("\t\tfailure(%d) res = %d", __LINE__, res);
    }
    return ret;
}

static int test24(void)
{
    bstring b;
    int ret = 0;
    debug
        ("TEST: int bninchr (const_bstring s1, int pos, const_bstring s2);");
    ret += test24_0(NULL, 0, NULL, BSTR_ERR);
    ret += test24_0(&emptyBstring, 0, NULL, BSTR_ERR);
    ret += test24_0(NULL, 0, &emptyBstring, BSTR_ERR);
    ret += test24_0(&shortBstring, 3, &badBstring1, BSTR_ERR);
    ret += test24_0(&badBstring1, 3, &shortBstring, BSTR_ERR);
    ret += test24_0(&emptyBstring, 0, &emptyBstring, BSTR_ERR);
    ret += test24_0(&shortBstring, 0, &emptyBstring, BSTR_ERR);
    ret += test24_0(&shortBstring, 0, &shortBstring, BSTR_ERR);
    ret += test24_0(&shortBstring, 1, &shortBstring, BSTR_ERR);
    ret += test24_0(&longBstring, 3, &shortBstring, 4);
    ret += test24_0(&longBstring, 3, b = bstrcpy(&shortBstring), 4);
    bdestroy(b);
    ret += test24_0(&longBstring, -1, &shortBstring, BSTR_ERR);
    ret += test24_0(&longBstring, 1000, &shortBstring, BSTR_ERR);
    ret += test24_0(&xxxxxBstring, 0, &shortBstring, 0);
    ret += test24_0(&xxxxxBstring, 1, &shortBstring, 1);
    ret += test24_0(&emptyBstring, 0, &shortBstring, BSTR_ERR);
    ret += test24_0(&longBstring, 0, &shortBstring, 0);
    ret += test24_0(&longBstring, 10, &shortBstring, 15);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test25_0(bstring s1, int pos, const_bstring s2, int res)
{
    int rv, ret = 0;
    debug(".\tbninchrr (%s, %d, %s) = ", dumpBstring(s1), pos,
            dumpBstring(s2));
    rv = bninchrr(s1, pos, s2);
    debug("%d", rv);
    ret += (rv != res);
    if (ret) {
        debug("\t\tfailure(%d) res = %d", __LINE__, res);
    }
    return ret;
}

static int test25(void)
{
    bstring b;
    int ret = 0;
    debug
        ("TEST: int bninchrr (const_bstring s1, int pos, const_bstring s2);");
    ret += test25_0(NULL, 0, NULL, BSTR_ERR);
    ret += test25_0(&emptyBstring, 0, NULL, BSTR_ERR);
    ret += test25_0(NULL, 0, &emptyBstring, BSTR_ERR);
    ret += test25_0(&emptyBstring, 0, &emptyBstring, BSTR_ERR);
    ret += test25_0(&shortBstring, 0, &emptyBstring, BSTR_ERR);
    ret += test25_0(&shortBstring, 0, &badBstring1, BSTR_ERR);
    ret += test25_0(&badBstring1, 0, &shortBstring, BSTR_ERR);
    ret += test25_0(&shortBstring, 0, &shortBstring, BSTR_ERR);
    ret += test25_0(&shortBstring, 4, &shortBstring, BSTR_ERR);
    ret += test25_0(&longBstring, 10, &shortBstring, 9);
    ret += test25_0(&longBstring, 10, b = bstrcpy(&shortBstring), 9);
    bdestroy(b);
    ret += test25_0(&xxxxxBstring, 4, &shortBstring, 4);
    ret += test25_0(&emptyBstring, 0, &shortBstring, BSTR_ERR);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test26_0(bstring b0, int pos, int len, const_bstring b1,
        unsigned char fill, char *res)
{
    bstring b2;
    int rv, ret = 0;
    if (b0 != NULL && b0->data != NULL && b0->slen >= 0
            && b1 != NULL && b1->data != NULL && b1->slen >= 0) {
        b2 = bstrcpy(b0);
        bwriteprotect(*b2);
        debug(".\tbreplace (%s, ", dumpBstring(b2));
        rv = breplace(b2, pos, len, b1, fill);
        ret += (rv == 0);
        if (!biseq(b0, b2))
            ret++;
        debug("%d, %d, %s, %02X) = %s", pos, len, dumpBstring(b1),
                fill, dumpBstring(b2));
        bwriteallow(*b2);
        debug(".\tbreplace (%s, ", dumpBstring(b2));
        rv = breplace(b2, pos, len, b1, fill);
        if (b1) {
            ret += (pos < 0) && (b2->slen != b0->slen);
            ret += ((rv == 0) != (pos >= 0 && pos <= b2->slen));
        }
        ret += (res == NULL) || ((int)strlen(res) > b2->slen) 
            ||(0 != memcmp(b2->data, res, b2->slen));
        ret += b2->data[b2->slen] != '\0';
        debug("%d, %d, %s, %02X) = %s", pos, len, dumpBstring(b1),
                fill, dumpBstring(b2));
        bdestroy(b2);
    } else {
        ret += (BSTR_ERR != (rv = breplace(b0, pos, len, b1, fill)));
        debug(".\tbreplace (%s, %d, %d, %s, %02X) = %d",
                dumpBstring(b0), pos, len, dumpBstring(b1), fill, rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test26(void)
{
    int ret = 0;
    debug
        ("TEST: int breplace (bstring b0, int pos, int len, const_bstring b1, unsigned char fill);");

    /* tests with NULL */ 
    ret += test26_0(NULL, 0, 0, NULL, (unsigned char)'?', NULL);
    ret +=
        test26_0(NULL, 0, 0, &emptyBstring, (unsigned char)'?', NULL);
    ret +=
        test26_0(&badBstring1, 1, 3, &shortBstring, (unsigned char)'?',
                NULL);
    ret +=
        test26_0(&shortBstring, 1, 3, &badBstring1, (unsigned char)'?',
                NULL);

    /* normal operation tests */ 
    ret +=
        test26_0(&emptyBstring, 0, 0, &emptyBstring, (unsigned char)'?',
                "");
    ret +=
        test26_0(&emptyBstring, 5, 0, &emptyBstring, (unsigned char)'?',
                "?????");
    ret +=
        test26_0(&emptyBstring, 5, 0, &shortBstring, (unsigned char)'?',
                "?????bogus");
    ret +=
        test26_0(&shortBstring, 0, 0, &emptyBstring, (unsigned char)'?',
                "bogus");
    ret +=
        test26_0(&emptyBstring, 0, 0, &shortBstring, (unsigned char)'?',
                "bogus");
    ret +=
        test26_0(&shortBstring, 0, 0, &shortBstring, (unsigned char)'?',
                "bogusbogus");
    ret +=
        test26_0(&shortBstring, 1, 3, &shortBstring, (unsigned char)'?',
                "bboguss");
    ret +=
        test26_0(&shortBstring, 3, 8, &shortBstring, (unsigned char)'?',
                "bogbogus");
    ret +=
        test26_0(&shortBstring, -1, 0, &shortBstring,
                (unsigned char)'?', "bogus");
    ret +=
        test26_0(&shortBstring, 2, 0, &shortBstring, (unsigned char)'?',
                "bobogusgus");
    ret +=
        test26_0(&shortBstring, 6, 0, &shortBstring, (unsigned char)'?',
                "bogus?bogus");
    ret +=
        test26_0(&shortBstring, 6, 0, NULL, (unsigned char)'?',
                "bogus");
    debug("\t# failures: %d", ret);
    return ret;
}

static int test27_0(bstring b0, const_bstring b1, const char *res)
{
    bstring b2;
    int rv, ret = 0;
    if (b0 != NULL && b0->data != NULL && b0->slen >= 0
            && b1 != NULL && b1->data != NULL && b1->slen >= 0) {
        b2 = bstrcpy(b0);
        bwriteprotect(*b2);
        debug(".\tbassign (%s, ", dumpBstring(b2));
        rv = bassign(b2, b1);
        ret += (rv == 0);
        if (!biseq(b0, b2))
            ret++;
        debug("%s) = %s", dumpBstring(b1), dumpBstring(b2));
        bwriteallow(*b2);
        debug(".\tbassign (%s, ", dumpBstring(b2));
        rv = bassign(b2, b1);
        debug("%s) = %s", dumpBstring(b1), dumpBstring(b2));
        if (b1)
            ret += (b2->slen != b1->slen);
        ret += ((0 != rv) && (b1 != NULL)) || ((0 == rv)
                && (b1 == NULL));
        ret += (res == NULL)
            || ((int)strlen(res) != b2->slen)  ||(0 !=
                    memcmp(b2->data, res,
                        b2->slen));
        ret += b2->data[b2->slen] != '\0';
        bdestroy(b2);
    } else {
        ret += (BSTR_ERR != (rv = bassign(b0, b1)));
        debug(".\tbassign (%s, %s) = %d", dumpBstring(b0),
                dumpBstring(b1), rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test27(void)
{
    int ret = 0;
    debug("TEST: int bassign (bstring b0, const_bstring b1);");

    /* tests with NULL */ 
    ret += test27_0(NULL, NULL, NULL);
    ret += test27_0(NULL, &emptyBstring, NULL);
    ret += test27_0(&emptyBstring, NULL, "");
    ret += test27_0(&badBstring1, &emptyBstring, NULL);
    ret += test27_0(&badBstring2, &emptyBstring, NULL);
    ret += test27_0(&emptyBstring, &badBstring1, NULL);
    ret += test27_0(&emptyBstring, &badBstring2, NULL);

    /* normal operation tests on all sorts of subranges */ 
    ret += test27_0(&emptyBstring, &emptyBstring, "");
    ret += test27_0(&emptyBstring, &shortBstring, "bogus");
    ret += test27_0(&shortBstring, &emptyBstring, "");
    ret += test27_0(&shortBstring, &shortBstring, "bogus");
    debug("\t# failures: %d", ret);
    return ret;
}

static int test28_0(bstring s1, int c, int res)
{
    int rv, ret = 0;
    debug(".\tbstrchr (%s, %d) = ", dumpBstring(s1), c);
    rv = bstrchr(s1, c);
    debug("%d", rv);
    ret += (rv != res);
    if (ret) {
        debug("\t\tfailure(%d) res = %d", __LINE__, res);
    }
    return ret;
}

static int test28_1(bstring s1, int c, int res)
{
    int rv, ret = 0;
    debug(".\tbstrrchr (%s, %d) = ", dumpBstring(s1), c);
    rv = bstrrchr(s1, c);
    debug("%d", rv);
    ret += (rv != res);
    if (ret) {
        debug("\t\tfailure(%d) res = %d rv = %d", __LINE__, res, rv);
    }
    return ret;
}

static int test28_2(bstring s1, int c, int pos, int res)
{
    int rv, ret = 0;
    debug(".\tbstrchrp (%s, %d, %d) = ", dumpBstring(s1), c, pos);
    rv = bstrchrp(s1, c, pos);
    debug("%d", rv);
    ret += (rv != res);
    if (ret) {
        debug("\t\tfailure(%d) res = %d", __LINE__, res);
    }
    return ret;
}

static int test28_3(bstring s1, int c, int pos, int res)
{
    int rv, ret = 0;
    debug(".\tbstrrchrp (%s, %d, %d) = ", dumpBstring(s1), c, pos);
    rv = bstrrchrp(s1, c, pos);
    debug("%d", rv);
    ret += (rv != res);
    if (ret) {
        debug("\t\tfailure(%d) res = %d rv = %d", __LINE__, res, rv);
    }
    return ret;
}

static int test28(void)
{
    int ret = 0;
    debug("TEST: int bstrchr (const_bstring s1, int c);");
    ret += test28_0(NULL, 0, BSTR_ERR);
    ret += test28_0(&badBstring1, 'b', BSTR_ERR);
    ret += test28_0(&badBstring2, 's', BSTR_ERR);
    ret += test28_0(&emptyBstring, 0, BSTR_ERR);
    ret += test28_0(&shortBstring, 0, BSTR_ERR);
    ret += test28_0(&shortBstring, 'b', 0);
    ret += test28_0(&shortBstring, 's', 4);
    ret += test28_0(&shortBstring, 'q', BSTR_ERR);
    ret += test28_0(&xxxxxBstring, 0, BSTR_ERR);
    ret += test28_0(&xxxxxBstring, 'b', BSTR_ERR);
    ret += test28_0(&longBstring, 'i', 2);
    debug("TEST: int bstrrchr (const_bstring s1, int c);");
    ret += test28_1(NULL, 0, BSTR_ERR);
    ret += test28_1(&badBstring1, 'b', BSTR_ERR);
    ret += test28_1(&badBstring2, 's', BSTR_ERR);
    ret += test28_1(&emptyBstring, 0, BSTR_ERR);
    ret += test28_1(&shortBstring, 0, BSTR_ERR);
    ret += test28_1(&shortBstring, 'b', 0);
    ret += test28_1(&shortBstring, 's', 4);
    ret += test28_1(&shortBstring, 'q', BSTR_ERR);
    ret += test28_1(&xxxxxBstring, 0, BSTR_ERR);
    ret += test28_1(&xxxxxBstring, 'b', BSTR_ERR);
    ret += test28_1(&longBstring, 'i', 82);
    debug("TEST: int bstrchrp (const_bstring s1, int c, int pos);");
    ret += test28_2(NULL, 0, 0, BSTR_ERR);
    ret += test28_2(&badBstring1, 'b', 0, BSTR_ERR);
    ret += test28_2(&badBstring2, 's', 0, BSTR_ERR);
    ret += test28_2(&shortBstring, 'b', -1, BSTR_ERR);
    ret += test28_2(&shortBstring, 'b', shortBstring.slen, BSTR_ERR);
    ret += test28_2(&emptyBstring, 0, 0, BSTR_ERR);
    ret += test28_2(&shortBstring, 0, 0, BSTR_ERR);
    ret += test28_2(&shortBstring, 'b', 0, 0);
    ret += test28_2(&shortBstring, 'b', 1, BSTR_ERR);
    ret += test28_2(&shortBstring, 's', 0, 4);
    ret += test28_2(&shortBstring, 'q', 0, BSTR_ERR);
    debug("TEST: int bstrrchrp (const_bstring s1, int c, int pos);");
    ret += test28_3(NULL, 0, 0, BSTR_ERR);
    ret += test28_3(&badBstring1, 'b', 0, BSTR_ERR);
    ret += test28_3(&badBstring2, 's', 0, BSTR_ERR);
    ret += test28_3(&shortBstring, 'b', -1, BSTR_ERR);
    ret += test28_3(&shortBstring, 'b', shortBstring.slen, BSTR_ERR);
    ret += test28_3(&emptyBstring, 0, 0, BSTR_ERR);
    ret += test28_3(&shortBstring, 0, 0, BSTR_ERR);
    ret += test28_3(&shortBstring, 'b', 0, 0);
    ret += test28_3(&shortBstring, 'b', shortBstring.slen - 1, 0);
    ret += test28_3(&shortBstring, 's', shortBstring.slen - 1, 4);
    ret += test28_3(&shortBstring, 's', 0, BSTR_ERR);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test29_0(bstring b0, char *s, const char *res)
{
    bstring b2;
    int rv, ret = 0;
    if (b0 != NULL && b0->data != NULL && b0->slen >= 0) {
        b2 = bstrcpy(b0);
        bwriteprotect(*b2);
        debug(".\tbcatcstr (%s, ", dumpBstring(b2));
        rv = bcatcstr(b2, s);
        ret += (rv == 0);
        if (!biseq(b0, b2))
            ret++;
        debug("%p) = %s", s, dumpBstring(b2));
        bwriteallow(*b2);
        debug(".\tbcatcstr (%s, ", dumpBstring(b2));
        rv = bcatcstr(b2, s);
        debug("%p) = %s", s, dumpBstring(b2));
        if (s)
            ret += (b2->slen != b0->slen + (int)strlen(s));
        ret += ((0 != rv) && (s != NULL)) || ((0 == rv)
                && (s == NULL));
        ret += (res == NULL)
            || ((int)strlen(res) != b2->slen)  ||(0 !=
                    memcmp(b2->data, res,
                        b2->slen));
        ret += b2->data[b2->slen] != '\0';
        bdestroy(b2);
    } else {
        ret += (BSTR_ERR != (rv = bcatcstr(b0, s)));
        debug(".\tbcatcstr (%s, %p) = %d", dumpBstring(b0), s, rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test29(void)
{
    int ret = 0;
    debug("TEST: int bcatcstr (bstring b0, const char * s);");

    /* tests with NULL */ 
    ret += test29_0(NULL, NULL, NULL);
    ret += test29_0(NULL, "", NULL);
    ret += test29_0(&emptyBstring, NULL, "");
    ret += test29_0(&badBstring1, "bogus", NULL);
    ret += test29_0(&badBstring2, "bogus", NULL);

    /* normal operation tests on all sorts of subranges */ 
    ret += test29_0(&emptyBstring, "", "");
    ret += test29_0(&emptyBstring, "bogus", "bogus");
    ret += test29_0(&shortBstring, "", "bogus");
    ret += test29_0(&shortBstring, "bogus", "bogusbogus");
    debug("\t# failures: %d", ret);
    return ret;
}

static int test30_0(bstring b0, const unsigned char *s, int len,
        const char *res)
{
    bstring b2;
    int rv, ret = 0;
    if (b0 != NULL && b0->data != NULL && b0->slen >= 0) {
        b2 = bstrcpy(b0);
        bwriteprotect(*b2);
        debug(".\tbcatblk (%s, ", dumpBstring(b2));
        rv = bcatblk(b2, s, len);
        ret += (rv == 0);
        if (!biseq(b0, b2))
            ret++;
        debug("%p) = %s", s, dumpBstring(b2));
        bwriteallow(*b2);
        debug(".\tbcatblk (%s, ", dumpBstring(b2));
        rv = bcatblk(b2, s, len);
        debug("%p) = %s", s, dumpBstring(b2));
        if (s) {
            if (len >= 0)
                ret += (b2->slen != b0->slen + len);

            else
                ret += (b2->slen != b0->slen);
        }
        ret += ((0 != rv) && (s != NULL && len >= 0)) || ((0 == rv)
                && (s == NULL
                    || len <
                    0));
        ret += (res == NULL)
            || ((int)strlen(res) != b2->slen)  ||(0 !=
                    memcmp(b2->data, res,
                        b2->slen));
        ret += b2->data[b2->slen] != '\0';
        bdestroy(b2);
    } else {
        ret += (BSTR_ERR != (rv = bcatblk(b0, s, len)));
        debug(".\tbcatblk (%s, %p, %d) = %d", dumpBstring(b0), s, len,
                rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test30(void)
{
    int ret = 0;
    debug("TEST: int bcatblk (bstring b0, const char * s);");

    /* tests with NULL */ 
    ret += test30_0(NULL, NULL, 0, NULL);
    ret += test30_0(NULL, (unsigned char *)"", 0, NULL);
    ret += test30_0(&emptyBstring, NULL, 0, "");
    ret += test30_0(&emptyBstring, NULL, -1, "");
    ret += test30_0(&badBstring1, NULL, 0, NULL);
    ret += test30_0(&badBstring2, NULL, 0, NULL);

    /* normal operation tests on all sorts of subranges */ 
    ret += test30_0(&emptyBstring, (unsigned char *)"", -1, "");
    ret += test30_0(&emptyBstring, (unsigned char *)"", 0, "");
    ret +=
        test30_0(&emptyBstring, (unsigned char *)"bogus", 5, "bogus");
    ret += test30_0(&shortBstring, (unsigned char *)"", 0, "bogus");
    ret +=
        test30_0(&shortBstring, (unsigned char *)"bogus", 5,
                "bogusbogus");
    ret +=
        test30_0(&shortBstring, (unsigned char *)"bogus", -1, "bogus");
    debug("\t# failures: %d", ret);
    return ret;
}

static int test31_0(bstring b0, const_bstring find,
        const_bstring replace, int pos, char *res)
{
    bstring b2;
    int rv, ret = 0;
    if (b0 != NULL && b0->data != NULL && b0->slen >= 0
            && find != NULL && find->data != NULL && find->slen >= 0
            && replace != NULL && replace->data != NULL
            && replace->slen >= 0) {
        b2 = bstrcpy(b0);
        bwriteprotect(*b2);
        debug(".\tbfindreplace (%s, %s, %s, %d) = ", dumpBstring(b2),
                dumpBstring(find), dumpBstring(replace), pos);
        rv = bfindreplace(b2, find, replace, pos);
        ret += (rv == 0);
        if (!biseq(b0, b2))
            ret++;
        debug("%d", rv);
        bwriteallow(*b2);
        debug(".\tbfindreplace (%s, %s, %s, %d)", dumpBstring(b2),
                dumpBstring(find), dumpBstring(replace), pos);
        rv = bfindreplace(b2, find, replace, pos);
        ret += (res == NULL) || ((int)strlen(res) > b2->slen) 
            ||(0 != memcmp(b2->data, res, b2->slen));
        ret += b2->data[b2->slen] != '\0';
        debug(" -> %s", dumpBstring(b2));
        bdestroy(b2);
    } else {
        ret +=
            (BSTR_ERR != (rv = bfindreplace(b0, find, replace, pos)));
        debug(".\tbfindreplace (%s, %s, %s, %d) = %d", dumpBstring(b0),
                dumpBstring(find), dumpBstring(replace), pos, rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test31_1(bstring b0, const_bstring find,
        const_bstring replace, int pos, char *res)
{
    bstring b2;
    int rv, ret = 0;
    if (b0 != NULL && b0->data != NULL && b0->slen >= 0
            && find != NULL && find->data != NULL && find->slen >= 0
            && replace != NULL && replace->data != NULL
            && replace->slen >= 0) {
        b2 = bstrcpy(b0);
        bwriteprotect(*b2);
        debug(".\tbfindreplacecaseless (%s, %s, %s, %d) = ",
                dumpBstring(b2), dumpBstring(find),
                dumpBstring(replace), pos);
        rv = bfindreplacecaseless(b2, find, replace, pos);
        ret += (rv == 0);
        if (!biseq(b0, b2))
            ret++;
        debug("%d", rv);
        bwriteallow(*b2);
        debug(".\tbfindreplacecaseless (%s, %s, %s, %d)",
                dumpBstring(b2), dumpBstring(find),
                dumpBstring(replace), pos);
        rv = bfindreplacecaseless(b2, find, replace, pos);
        ret += (res == NULL) || ((int)strlen(res) > b2->slen) 
            ||(0 != memcmp(b2->data, res, b2->slen));
        ret += b2->data[b2->slen] != '\0';
        debug(" -> %s", dumpBstring(b2));
        bdestroy(b2);
    } else {
        ret +=
            (BSTR_ERR !=
             (rv = bfindreplacecaseless(b0, find, replace, pos)));
        debug(".\tbfindreplacecaseless (%s, %s, %s, %d) = %d",
                dumpBstring(b0), dumpBstring(find), dumpBstring(replace),
                pos, rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}


#define LOTS_OF_S "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
static int test31(void)
{
    int ret = 0;
    struct tagbstring t0 = bsStatic("funny");
    struct tagbstring t1 = bsStatic("weird");
    struct tagbstring t2 = bsStatic("s");
    struct tagbstring t3 = bsStatic("long");
    struct tagbstring t4 = bsStatic("big");
    struct tagbstring t5 = bsStatic("ss");
    struct tagbstring t6 = bsStatic("sstsst");
    struct tagbstring t7 = bsStatic("xx" LOTS_OF_S "xx");
    struct tagbstring t8 = bsStatic("S");
    struct tagbstring t9 = bsStatic("LONG");
    debug
        ("TEST: int bfindreplace (bstring b, const_bstring f, const_bstring r, int pos);");

    /* tests with NULL */ 
    ret += test31_0(NULL, NULL, NULL, 0, NULL);
    ret +=
        test31_0(&shortBstring, NULL, &t1, 0,
                (char *)shortBstring.data);
    ret +=
        test31_0(&shortBstring, &t2, NULL, 0,
                (char *)shortBstring.data);
    ret += test31_0(&badBstring1, &t2, &t1, 0, NULL);
    ret += test31_0(&badBstring2, &t2, &t1, 0, NULL);

    /* normal operation tests */ 
    ret +=
        test31_0(&longBstring, &shortBstring, &t0, 0,
                "This is a funny but reasonably long string.  Just long enough to cause some mallocing.");
    ret +=
        test31_0(&longBstring, &t2, &t1, 0,
                "Thiweird iweird a boguweird but reaweirdonably long weirdtring.  Juweirdt long enough to cauweirde weirdome mallocing.");
    ret += test31_0(&shortBstring, &t2, &t1, 0, "boguweird");
    ret += test31_0(&shortBstring, &t8, &t1, 0, "bogus");
    ret +=
        test31_0(&longBstring, &t2, &t1, 27,
                "This is a bogus but reasonably long weirdtring.  Juweirdt long enough to cauweirde weirdome mallocing.");
    ret +=
        test31_0(&longBstring, &t3, &t4, 0,
                "This is a bogus but reasonably big string.  Just big enough to cause some mallocing.");
    ret +=
        test31_0(&longBstring, &t9, &t4, 0,
                "This is a bogus but reasonably long string.  Just long enough to cause some mallocing.");
    ret += test31_0(&t6, &t2, &t5, 0, "sssstsssst");
    ret += test31_0(&t7, &t2, &t5, 0, "xx" LOTS_OF_S LOTS_OF_S "xx");
    debug
        ("TEST: int bfindreplacecaseless (bstring b, const_bstring f, const_bstring r, int pos);");

    /* tests with NULL */ 
    ret += test31_1(NULL, NULL, NULL, 0, NULL);
    ret +=
        test31_1(&shortBstring, NULL, &t1, 0,
                (char *)shortBstring.data);
    ret +=
        test31_1(&shortBstring, &t2, NULL, 0,
                (char *)shortBstring.data);
    ret += test31_1(&badBstring1, &t2, &t1, 0, NULL);
    ret += test31_1(&badBstring2, &t2, &t1, 0, NULL);

    /* normal operation tests */ 
    ret +=
        test31_1(&longBstring, &shortBstring, &t0, 0,
                "This is a funny but reasonably long string.  Just long enough to cause some mallocing.");
    ret +=
        test31_1(&longBstring, &t2, &t1, 0,
                "Thiweird iweird a boguweird but reaweirdonably long weirdtring.  Juweirdt long enough to cauweirde weirdome mallocing.");
    ret += test31_1(&shortBstring, &t2, &t1, 0, "boguweird");
    ret += test31_1(&shortBstring, &t8, &t1, 0, "boguweird");
    ret +=
        test31_1(&longBstring, &t2, &t1, 27,
                "This is a bogus but reasonably long weirdtring.  Juweirdt long enough to cauweirde weirdome mallocing.");
    ret +=
        test31_1(&longBstring, &t3, &t4, 0,
                "This is a bogus but reasonably big string.  Just big enough to cause some mallocing.");
    ret +=
        test31_1(&longBstring, &t9, &t4, 0,
                "This is a bogus but reasonably big string.  Just big enough to cause some mallocing.");
    ret += test31_1(&t6, &t2, &t5, 0, "sssstsssst");
    ret += test31_1(&t6, &t8, &t5, 0, "sssstsssst");
    ret += test31_1(&t7, &t2, &t5, 0, "xx" LOTS_OF_S LOTS_OF_S "xx");
    debug("\t# failures: %d", ret);
    return ret;
}

static int test32_0(const_bstring b, const char *s, int res)
{
    int rv, ret = 0;
    ret += (res != (rv = biseqcstr(b, s)));
    debug(".\tbiseqcstr (%s, %p:<%s>) = %d", dumpBstring(b), s,
            (s ? s : NULL), rv);
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %d)", __LINE__, ret, res);
    }
    return ret;
}

static int test32_1(const_bstring b, const char *s, int res)
{
    int rv, ret = 0;
    ret += (res != (rv = biseqcstrcaseless(b, s)));
    debug(".\tbiseqcstrcaseless (%s, %p:<%s>) = %d", dumpBstring(b), s,
            (s ? s : NULL), rv);
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %d)", __LINE__, ret, res);
    }
    return ret;
}

static int test32(void)
{
    int ret = 0;
    debug("TEST: int biseqcstr (const_bstring b, const char * s);");

    /* tests with NULL */ 
    ret += test32_0(NULL, NULL, BSTR_ERR);
    ret += test32_0(&emptyBstring, NULL, BSTR_ERR);
    ret += test32_0(NULL, "", BSTR_ERR);
    ret += test32_0(&badBstring1, "", BSTR_ERR);
    ret += test32_0(&badBstring2, "bogus", BSTR_ERR);

    /* normal operation tests on all sorts of subranges */ 
    ret += test32_0(&emptyBstring, "", 1);
    ret += test32_0(&shortBstring, "bogus", 1);
    ret += test32_0(&emptyBstring, "bogus", 0);
    ret += test32_0(&shortBstring, "", 0);
    {
        bstring b = bstrcpy(&shortBstring);
        b->data[1]++;
        ret += test32_0(b, (char *)shortBstring.data, 0);
        bdestroy(b);
    }  debug
    ("TEST: int biseqcstrcaseless (const_bstring b, const char * s);");

    /* tests with NULL */ 
    ret += test32_1(NULL, NULL, BSTR_ERR);
    ret += test32_1(&emptyBstring, NULL, BSTR_ERR);
    ret += test32_1(NULL, "", BSTR_ERR);
    ret += test32_1(&badBstring1, "", BSTR_ERR);
    ret += test32_1(&badBstring2, "bogus", BSTR_ERR);

    /* normal operation tests on all sorts of subranges */ 
    ret += test32_1(&emptyBstring, "", 1);
    ret += test32_1(&shortBstring, "bogus", 1);
    ret += test32_1(&shortBstring, "BOGUS", 1);
    ret += test32_1(&emptyBstring, "bogus", 0);
    ret += test32_1(&shortBstring, "", 0);
    {
        bstring b = bstrcpy(&shortBstring);
        b->data[1]++;
        ret += test32_1(b, (char *)shortBstring.data, 0);
        bdestroy(b);
    }  if (ret)
    debug("\t# failures: %d", ret);
    return ret;
}

static int test33_0(bstring b0, const char *res)
{
    bstring b2;
    int rv, ret = 0;
    if (b0 != NULL && b0->data != NULL && b0->slen >= 0) {
        b2 = bstrcpy(b0);
        bwriteprotect(*b2);
        debug(".\tbtoupper (%s)", dumpBstring(b2));
        rv = btoupper(b2);
        ret += (rv == 0);
        if (!biseq(b0, b2))
            ret++;
        debug(" = %s", dumpBstring(b2));
        bwriteallow(*b2);
        debug(".\tbtoupper (%s)", dumpBstring(b2));
        rv = btoupper(b2);
        debug(" = %s", dumpBstring(b2));
        ret += (b2->slen != b0->slen);
        ret += (0 != rv);
        ret += (res == NULL) || ((int)strlen(res) != b2->slen) 
            ||(0 != memcmp(b2->data, res, b2->slen));
        ret += b2->data[b2->slen] != '\0';
        bdestroy(b2);
    } else {
        ret += (BSTR_ERR != (rv = btoupper(b0)));
        debug(".\tbtoupper (%s) = %d", dumpBstring(b0), rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test33(void)
{
    int ret = 0;
    debug("TEST: int btoupper (bstring b);");

    /* tests with NULL */ 
    ret += test33_0(NULL, NULL);
    ret += test33_0(&badBstring1, NULL);
    ret += test33_0(&badBstring2, NULL);

    /* normal operation tests on all sorts of subranges */ 
    ret += test33_0(&emptyBstring, "");
    ret += test33_0(&shortBstring, "BOGUS");
    ret +=
        test33_0(&longBstring,
                "THIS IS A BOGUS BUT REASONABLY LONG STRING.  JUST LONG ENOUGH TO CAUSE SOME MALLOCING.");
    if (ret)
        debug("\t# failures: %d", ret);
    return ret;
}

static int test34_0(bstring b0, const char *res)
{
    bstring b2;
    int rv, ret = 0;
    if (b0 != NULL && b0->data != NULL && b0->slen >= 0) {
        b2 = bstrcpy(b0);
        bwriteprotect(*b2);
        debug(".\tbtolower (%s)", dumpBstring(b2));
        rv = btolower(b2);
        ret += (rv == 0);
        if (!biseq(b0, b2))
            ret++;
        debug(" = %s", dumpBstring(b2));
        bwriteallow(*b2);
        debug(".\tbtolower (%s)", dumpBstring(b2));
        rv = btolower(b2);
        debug(" = %s", dumpBstring(b2));
        ret += (b2->slen != b0->slen);
        ret += (0 != rv);
        ret += (res == NULL) || ((int)strlen(res) != b2->slen) 
            ||(0 != memcmp(b2->data, res, b2->slen));
        ret += b2->data[b2->slen] != '\0';
        bdestroy(b2);
    } else {
        ret += (BSTR_ERR != (rv = btolower(b0)));
        debug(".\tbtolower (%s) = %d", dumpBstring(b0), rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test34(void)
{
    int ret = 0;
    debug("TEST: int btolower (bstring b);");

    /* tests with NULL */ 
    ret += test34_0(NULL, NULL);
    ret += test34_0(&badBstring1, NULL);
    ret += test34_0(&badBstring2, NULL);

    /* normal operation tests on all sorts of subranges */ 
    ret += test34_0(&emptyBstring, "");
    ret += test34_0(&shortBstring, "bogus");
    ret +=
        test34_0(&longBstring,
                "this is a bogus but reasonably long string.  just long enough to cause some mallocing.");
    if (ret)
        debug("\t# failures: %d", ret);
    return ret;
}

static int test35_0(const_bstring b0, const_bstring b1, int res)
{
    int rv, ret = 0;
    ret += (res != (rv = bstricmp(b0, b1)));
    debug(".\tbstricmp (%s, %s) = %d", dumpBstring(b0),
            dumpBstring(b1), rv);
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %d)", __LINE__, ret, res);
    }
    return ret;
}

static int test35(void)
{
    int ret = 0;
    struct tagbstring t0 = bsStatic("bOgUs");
    struct tagbstring t1 = bsStatic("bOgUR");
    struct tagbstring t2 = bsStatic("bOgUt");
    debug
        ("TEST: int bstricmp (const_bstring b0, const_bstring b1);");

    /* tests with NULL */ 
    ret += test35_0(NULL, NULL, SHRT_MIN);
    ret += test35_0(&emptyBstring, NULL, SHRT_MIN);
    ret += test35_0(NULL, &emptyBstring, SHRT_MIN);
    ret += test35_0(&emptyBstring, &badBstring1, SHRT_MIN);
    ret += test35_0(&badBstring1, &emptyBstring, SHRT_MIN);
    ret += test35_0(&shortBstring, &badBstring2, SHRT_MIN);
    ret += test35_0(&badBstring2, &shortBstring, SHRT_MIN);

    /* normal operation tests on all sorts of subranges */ 
    ret += test35_0(&emptyBstring, &emptyBstring, 0);
    ret += test35_0(&shortBstring, &t0, 0);
    ret +=
        test35_0(&shortBstring, &t1,
                tolower(shortBstring.data[4]) - tolower(t1.data[4]));
    ret +=
        test35_0(&shortBstring, &t2,
                tolower(shortBstring.data[4]) - tolower(t2.data[4]));
    t0.slen++;
    ret += test35_0(&shortBstring, &t0, -(UCHAR_MAX + 1));
    ret += test35_0(&t0, &shortBstring, (UCHAR_MAX + 1));
    if (ret)
        debug("\t# failures: %d", ret);
    return ret;
}

static int test36_0(const_bstring b0, const_bstring b1, int n,
        int res)
{
    int rv, ret = 0;
    ret += (res != (rv = bstrnicmp(b0, b1, n)));
    debug(".\tbstrnicmp (%s, %s, %d) = %d", dumpBstring(b0),
            dumpBstring(b1), n, rv);
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %d)", __LINE__, ret, res);
    }
    return ret;
}

static int test36(void)
{
    int ret = 0;
    struct tagbstring t0 = bsStatic("bOgUs");
    struct tagbstring t1 = bsStatic("bOgUR");
    struct tagbstring t2 = bsStatic("bOgUt");
    debug
        ("TEST: int bstrnicmp (const_bstring b0, const_bstring b1);");

    /* tests with NULL */ 
    ret += test36_0(NULL, NULL, 0, SHRT_MIN);
    ret += test36_0(&emptyBstring, NULL, 0, SHRT_MIN);
    ret += test36_0(NULL, &emptyBstring, 0, SHRT_MIN);
    ret += test36_0(&emptyBstring, &badBstring1, 0, SHRT_MIN);
    ret += test36_0(&badBstring1, &emptyBstring, 0, SHRT_MIN);
    ret += test36_0(&shortBstring, &badBstring2, 5, SHRT_MIN);
    ret += test36_0(&badBstring2, &shortBstring, 5, SHRT_MIN);

    /* normal operation tests on all sorts of subranges */ 
    ret += test36_0(&emptyBstring, &emptyBstring, 0, 0);
    ret += test36_0(&shortBstring, &t0, 0, 0);
    ret += test36_0(&shortBstring, &t0, 5, 0);
    ret += test36_0(&shortBstring, &t0, 4, 0);
    ret += test36_0(&shortBstring, &t0, 6, 0);
    ret +=
        test36_0(&shortBstring, &t1, 5,
                shortBstring.data[4] - t1.data[4]);
    ret += test36_0(&shortBstring, &t1, 4, 0);
    ret +=
        test36_0(&shortBstring, &t1, 6,
                shortBstring.data[4] - t1.data[4]);
    ret +=
        test36_0(&shortBstring, &t2, 5,
                shortBstring.data[4] - t2.data[4]);
    ret += test36_0(&shortBstring, &t2, 4, 0);
    ret +=
        test36_0(&shortBstring, &t2, 6,
                shortBstring.data[4] - t2.data[4]);
    t0.slen++;
    ret += test36_0(&shortBstring, &t0, 5, 0);
    ret += test36_0(&shortBstring, &t0, 6, -(UCHAR_MAX + 1));
    ret += test36_0(&t0, &shortBstring, 6, (UCHAR_MAX + 1));
    if (ret)
        debug("\t# failures: %d", ret);
    return ret;
}

static int test37_0(const_bstring b0, const_bstring b1, int res)
{
    int rv, ret = 0;
    ret += (res != (rv = biseqcaseless(b0, b1)));
    debug(".\tbiseqcaseless (%s, %s) = %d", dumpBstring(b0),
            dumpBstring(b1), rv);
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %d)", __LINE__, ret, res);
    }
    return ret;
}

static int test37(void)
{
    int ret = 0;
    struct tagbstring t0 = bsStatic("bOgUs");
    struct tagbstring t1 = bsStatic("bOgUR");
    struct tagbstring t2 = bsStatic("bOgUt");
    debug
        ("TEST: int biseqcaseless (const_bstring b0, const_bstring b1);");

    /* tests with NULL */ 
    ret += test37_0(NULL, NULL, BSTR_ERR);
    ret += test37_0(&emptyBstring, NULL, BSTR_ERR);
    ret += test37_0(NULL, &emptyBstring, BSTR_ERR);
    ret += test37_0(&emptyBstring, &badBstring1, BSTR_ERR);
    ret += test37_0(&badBstring1, &emptyBstring, BSTR_ERR);
    ret += test37_0(&shortBstring, &badBstring2, BSTR_ERR);
    ret += test37_0(&badBstring2, &shortBstring, BSTR_ERR);

    /* normal operation tests on all sorts of subranges */ 
    ret += test37_0(&emptyBstring, &emptyBstring, 1);
    ret += test37_0(&shortBstring, &t0, 1);
    ret += test37_0(&shortBstring, &t1, 0);
    ret += test37_0(&shortBstring, &t2, 0);
    if (ret)
        debug("\t# failures: %d", ret);
    return ret;
}

struct emuFile {
    int ofs;
    bstring contents;
};
static int test38_aux_bNgetc(struct emuFile *f)
{
    int v = EOF;
    if (NULL != f && EOF != (v = bchare(f->contents, f->ofs, EOF)))
        f->ofs++;
    return v;
}

static size_t test38_aux_bNread(void *buff, size_t elsize,
        size_t nelem, struct emuFile *f)
{
    char *b = (char *)buff;
    int v;
    size_t i, j, c = 0;
    if (NULL == f || NULL == b)
        return c;
    for (i = 0; i < nelem; i++)
        for (j = 0; j < elsize; j++) {
            v = test38_aux_bNgetc(f);
            if (EOF == v) {
                *b = (char)'\0';
                return c;
            } else {
                *b = (char)v;
                b++;
                c++;
            } }  return c;
}

static int test38_aux_bNopen(struct emuFile *f, bstring b)
{
    if (NULL == f || NULL == b)
        return -__LINE__;
    f->ofs = 0;
    f->contents = b;
    return 0;
}

static int test38(void)
{
    struct emuFile f;
    bstring b0, b1, b2, b3;
    int ret = 0;
    debug("TEST: bgets/breads test");
    test38_aux_bNopen(&f, &shortBstring);

    /* Creation/reads */ 
    b0 = bgets((bNgetc) test38_aux_bNgetc, &f, (char)'b');
    b1 = bread((bNread) test38_aux_bNread, &f);
    b2 = bgets((bNgetc) test38_aux_bNgetc, &f, (char)'\0');
    b3 = bread((bNread) test38_aux_bNread, &f);
    ret += 1 != biseqcstr(b0, "b");
    ret += 1 != biseqcstr(b1, "ogus");
    ret += NULL != b2;
    ret += 1 != biseqcstr(b3, "");

    /* Bogus accumulations */ 
    f.ofs = 0;
    ret +=
        0 <= bgetsa(NULL, (bNgetc) test38_aux_bNgetc, &f, (char)'o');
    ret += 0 <= breada(NULL, (bNread) test38_aux_bNread, &f);
    ret +=
        0 <= bgetsa(&shortBstring, (bNgetc) test38_aux_bNgetc, &f,
                (char)'o');
    ret += 0 <= breada(&shortBstring, (bNread) test38_aux_bNread, &f);

    /* Normal accumulations */ 
    ret +=
        0 > bgetsa(b0, (bNgetc) test38_aux_bNgetc, &f, (char)'o');
    ret += 0 > breada(b1, (bNread) test38_aux_bNread, &f);
    ret += 1 != biseqcstr(b0, "bbo");
    ret += 1 != biseqcstr(b1, "ogusgus");

    /* Attempt to append past end should do nothing */ 
    ret +=
        0 > bgetsa(b0, (bNgetc) test38_aux_bNgetc, &f, (char)'o');
    ret += 0 > breada(b1, (bNread) test38_aux_bNread, &f);
    ret += 1 != biseqcstr(b0, "bbo");
    ret += 1 != biseqcstr(b1, "ogusgus");
    bdestroy(b0);
    bdestroy(b1);
    bdestroy(b2);
    bdestroy(b3);
    if (ret)
        debug("\t# failures: %d", ret);
    return ret;
}

static int test39_0(const_bstring b, const_bstring lt,
        const_bstring rt, const_bstring t)
{
    bstring r;
    int ret = 0;
    ret += 0 <= bltrimws(NULL);
    ret += 0 <= brtrimws(NULL);
    ret += 0 <= btrimws(NULL);
    r = bstrcpy(b);
    bwriteprotect(*r);
    ret += 0 <= bltrimws(r);
    ret += 0 <= brtrimws(r);
    ret += 0 <= btrimws(r);
    bwriteallow(*r);
    ret += 0 != bltrimws(r);
    debug(".\tbltrim (%s) = %s", dumpBstring(b), dumpBstring(r));
    ret += !biseq(r, lt);
    bdestroy(r);
    r = bstrcpy(b);
    ret += 0 != brtrimws(r);
    debug(".\tbrtrim (%s) = %s", dumpBstring(b), dumpBstring(r));
    ret += !biseq(r, rt);
    bdestroy(r);
    r = bstrcpy(b);
    ret += 0 != btrimws(r);
    debug(".\tbtrim  (%s) = %s", dumpBstring(b), dumpBstring(r));
    ret += !biseq(r, t);
    bdestroy(r);
    return ret;
}

static int test39(void)
{
    int ret = 0;
    struct tagbstring t0 = bsStatic("   bogus string   ");
    struct tagbstring t1 = bsStatic("bogus string   ");
    struct tagbstring t2 = bsStatic("   bogus string");
    struct tagbstring t3 = bsStatic("bogus string");
    struct tagbstring t4 = bsStatic("     ");
    struct tagbstring t5 = bsStatic("");
    debug("TEST: trim functions");
    ret += test39_0(&t0, &t1, &t2, &t3);
    ret += test39_0(&t1, &t1, &t3, &t3);
    ret += test39_0(&t2, &t3, &t2, &t3);
    ret += test39_0(&t3, &t3, &t3, &t3);
    ret += test39_0(&t4, &t5, &t5, &t5);
    ret += test39_0(&t5, &t5, &t5, &t5);
    if (ret)
        debug("\t# failures: %d", ret);
    return ret;
}

static int test40_0(bstring b0, const_bstring b1, int left, int len,
        const char *res)
{
    bstring b2;
    int rv, ret = 0;
    if (b0 != NULL && b0->data != NULL && b0->slen >= 0
            && b1 != NULL && b1->data != NULL && b1->slen >= 0) {
        b2 = bstrcpy(b0);
        bwriteprotect(*b2);
        debug(".\tbassignmidstr (%s, ", dumpBstring(b2));
        rv = bassignmidstr(b2, b1, left, len);
        ret += (rv == 0);
        if (!biseq(b0, b2))
            ret++;
        debug("%s, %d, %d) = %s", dumpBstring(b1), left, len,
                dumpBstring(b2));
        bwriteallow(*b2);
        debug(".\tbassignmidstr (%s, ", dumpBstring(b2));
        rv = bassignmidstr(b2, b1, left, len);
        debug("%s, %d, %d) = %s", dumpBstring(b1), left, len,
                dumpBstring(b2));
        if (b1)
            ret += (b2->slen > len) | (b2->slen < 0);
        ret += ((0 != rv) && (b1 != NULL)) || ((0 == rv)
                && (b1 == NULL));
        ret += (res == NULL)
            || ((int)strlen(res) != b2->slen)  ||(0 !=
                    memcmp(b2->data, res,
                        b2->slen));
        ret += b2->data[b2->slen] != '\0';
        bdestroy(b2);
    } else {
        ret += (BSTR_ERR != (rv = bassignmidstr(b0, b1, left, len)));
        debug(".\tbassignmidstr (%s, %s, %d, %d) = %d",
                dumpBstring(b0), dumpBstring(b1), left, len, rv);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test40(void)
{
    int ret = 0;
    debug
        ("TEST: int bassignmidstr (bstring b0, const_bstring b1, int left, int len);");

    /* tests with NULL */ 
    ret += test40_0(NULL, NULL, 0, 1, NULL);
    ret += test40_0(NULL, &emptyBstring, 0, 1, NULL);
    ret += test40_0(&emptyBstring, NULL, 0, 1, "");
    ret += test40_0(&badBstring1, &emptyBstring, 0, 1, NULL);
    ret += test40_0(&badBstring2, &emptyBstring, 0, 1, NULL);
    ret += test40_0(&emptyBstring, &badBstring1, 0, 1, NULL);
    ret += test40_0(&emptyBstring, &badBstring2, 0, 1, NULL);

    /* normal operation tests on all sorts of subranges */ 
    ret += test40_0(&emptyBstring, &emptyBstring, 0, 1, "");
    ret += test40_0(&emptyBstring, &shortBstring, 1, 3, "ogu");
    ret += test40_0(&shortBstring, &emptyBstring, 0, 1, "");
    ret += test40_0(&shortBstring, &shortBstring, 1, 3, "ogu");
    ret += test40_0(&shortBstring, &shortBstring, -1, 4, "bog");
    ret += test40_0(&shortBstring, &shortBstring, 1, 9, "ogus");
    ret += test40_0(&shortBstring, &shortBstring, 9, 1, "");
    debug("\t# failures: %d", ret);
    return ret;
}

static int test41_0(bstring b1, int left, int len, const char *res)
{
    struct tagbstring t;
    bstring b2, b3;
    int ret = 0;
    if (b1 != NULL && b1->data != NULL && b1->slen >= 0) {
        b2 = bfromcstr("");
        bassignmidstr(b2, b1, left, len);
        bmid2tbstr(t, b1, left, len);
        b3 = bstrcpy(&t);
        debug(".\tbmid2tbstr (%s, %d, %d) = %s", dumpBstring(b1),
                left, len, dumpBstring(b3));
        ret += !biseq(&t, b2);
        bdestroy(b2);
        bdestroy(b3);
    } else {
        bmid2tbstr(t, b1, left, len);
        b3 = bstrcpy(&t);
        ret += t.slen != 0;
        debug(".\tbmid2tbstr (%s, %d, %d) = %s", dumpBstring(b1),
                left, len, dumpBstring(b3));
        bdestroy(b3);
    }
    if (ret) {
        debug("\t\tfailure(%d) = %d (res = %p", __LINE__, ret, res);
        if (res)
            debug(" = \"%s\"", res);
        debug(")");
    }
    return ret;
}

static int test41(void)
{
    int ret = 0;
    debug
        ("TEST: int bmid2tbstr (struct tagbstring &t, const_bstring b1, int left, int len);");

    /* tests with NULL */ 
    ret += test41_0(NULL, 0, 1, NULL);
    ret += test41_0(&emptyBstring, 0, 1, NULL);
    ret += test41_0(NULL, 0, 1, "");
    ret += test41_0(&emptyBstring, 0, 1, NULL);
    ret += test41_0(&emptyBstring, 0, 1, NULL);
    ret += test41_0(&badBstring1, 0, 1, NULL);
    ret += test41_0(&badBstring2, 0, 1, NULL);

    /* normal operation tests on all sorts of subranges */ 
    ret += test41_0(&emptyBstring, 0, 1, "");
    ret += test41_0(&shortBstring, 1, 3, "ogu");
    ret += test41_0(&emptyBstring, 0, 1, "");
    ret += test41_0(&shortBstring, 1, 3, "ogu");
    ret += test41_0(&shortBstring, -1, 4, "bog");
    ret += test41_0(&shortBstring, 1, 9, "ogus");
    ret += test41_0(&shortBstring, 9, 1, "");
    debug("\t# failures: %d", ret);
    return ret;
}

static int test42_0(const_bstring bi, int len, const char *res)
{
    bstring b;
    int rv, ret = 0;
    rv = btrunc(b = bstrcpy(bi), len);
    ret += (len >= 0) ? (rv < 0) : (rv >= 0);
    if (res)
        ret += (0 == biseqcstr(b, res));
    debug(".\tbtrunc (%s, %d) = %s", dumpBstring(bi), len,
            dumpBstring(b));
    bdestroy(b);
    return ret;
}

static int test42(void)
{
    int ret = 0;
    debug("TEST: int btrunc (bstring b, int n);");

    /* tests with NULL */ 
    ret += 0 <= btrunc(NULL, 2);
    ret += 0 <= btrunc(NULL, 0);
    ret += 0 <= btrunc(NULL, -1);

    /* write protected */ 
    ret += 0 <= btrunc(&shortBstring, 2);
    ret += 0 <= btrunc(&shortBstring, 0);
    ret += 0 <= btrunc(&shortBstring, -1);
    ret += test42_0(&emptyBstring, 10, "");
    ret += test42_0(&emptyBstring, 0, "");
    ret += test42_0(&emptyBstring, -1, NULL);
    ret += test42_0(&shortBstring, 10, "bogus");
    ret += test42_0(&shortBstring, 3, "bog");
    ret += test42_0(&shortBstring, 0, "");
    ret += test42_0(&shortBstring, -1, NULL);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test43(void)
{
    static struct tagbstring ts0 = bsStatic("");
    static struct tagbstring ts1 = bsStatic("    ");
    static struct tagbstring ts2 = bsStatic(" abc");
    static struct tagbstring ts3 = bsStatic("abc ");
    static struct tagbstring ts4 = bsStatic(" abc ");
    static struct tagbstring ts5 = bsStatic("abc");
    bstring tstrs[6] = {
        &ts0, &ts1, &ts2, &ts3, &ts4, &ts5};
    int ret = 0;
    int i;
    debug
        ("TEST: int btfromblk*trim (struct tagbstring t, void * s, int l);");
    for (i = 0; i < 6; i++) {
        struct tagbstring t;
        bstring b;
        btfromblkltrimws(t, tstrs[i]->data, tstrs[i]->slen);
        bltrimws(b = bstrcpy(tstrs[i]));
        if (!biseq(b, &t)) {
            ret++;
            bassign(b, &t);
            debug("btfromblkltrimws failure: <%s> -> <%s>",
                    tstrs[i]->data, b->data);
        }
        debug(".\tbtfromblkltrimws (\"%s\", \"%s\", %d)",
                (char *)bdatae(b, NULL), tstrs[i]->data, tstrs[i]->slen);
        bdestroy(b);
        btfromblkrtrimws(t, tstrs[i]->data, tstrs[i]->slen);
        brtrimws(b = bstrcpy(tstrs[i]));
        if (!biseq(b, &t)) {
            ret++;
            bassign(b, &t);
            debug("btfromblkrtrimws failure: <%s> -> <%s>",
                    tstrs[i]->data, b->data);
        }
        debug(".\tbtfromblkrtrimws (\"%s\", \"%s\", %d)",
                (char *)bdatae(b, NULL), tstrs[i]->data, tstrs[i]->slen);
        bdestroy(b);
        btfromblktrimws(t, tstrs[i]->data, tstrs[i]->slen);
        btrimws(b = bstrcpy(tstrs[i]));
        if (!biseq(b, &t)) {
            ret++;
            bassign(b, &t);
            debug("btfromblktrimws failure: <%s> -> <%s>",
                    tstrs[i]->data, b->data);
        }
        debug(".\tbtfromblktrimws (\"%s\", \"%s\", %d)",
                (char *)bdatae(b, NULL), tstrs[i]->data, tstrs[i]->slen);
        bdestroy(b);
    }  debug("\t# failures: %d", ret);
    return ret;
}

static int test44_0(const char *str)
{
    int ret = 0, v;
    bstring b = bfromcstr("");
    if (NULL == str) {
        ret += 0 <= bassigncstr(NULL, "test");
        debug(".\tbassigncstr (b = %s, NULL)",
                dumpBstring(b = bfromcstr("")));
        ret += 0 <= (v = bassigncstr(b, NULL));
        debug(" = %d; b -> %s", v, dumpBstring(b));
        ret += 0 <= bassigncstr(&shortBstring, NULL);
        bdestroy(b);
        return ret;
    }
    ret += 0 <= bassigncstr(NULL, str);
    debug(".\tbassigncstr (b = %s, \"%s\")",
            dumpBstring(b = bfromcstr("")), str);
    ret += 0 > (v = bassigncstr(b, str));
    debug(" = %d; b -> %s", v, dumpBstring(b));
    ret += 0 != strcmp(bdatae(b, ""), str);
    ret += ((size_t) b->slen) != strlen(str);
    ret += 0 > bassigncstr(b, "xxxxx");
    bwriteprotect(*b) 
        log_info(".\tbassigncstr (b = %s, \"%s\")", dumpBstring(b),
                str);
    ret += 0 <= (v = bassigncstr(b, str));
    debug(" = %d; b -> %s", v, dumpBstring(b));
    ret += 0 != strcmp(bdatae(b, ""), "xxxxx");
    ret += ((size_t) b->slen) != strlen("xxxxx");
    bwriteallow(*b)  ret += 0 <= bassigncstr(&shortBstring, str);
    bdestroy(b);
    debug(".\tbassigncstr (a = %s, \"%s\")",
            dumpBstring(&shortBstring), str);
    ret += 0 <= (v = bassigncstr(&shortBstring, str));
    debug(" = %d; a -> %s", v, dumpBstring(&shortBstring));
    return ret;
}

static int test44(void)
{
    int ret = 0;
    debug("TEST: int bassigncstr (bstring a, char * str);");

    /* tests with NULL */ 
    ret += test44_0(NULL);
    ret += test44_0(EMPTY_STRING);
    ret += test44_0(SHORT_STRING);
    ret += test44_0(LONG_STRING);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test45_0(const char *str)
{
    int ret = 0, v, len;
    bstring b = bfromcstr("");
    if (NULL == str) {
        ret += 0 <= bassignblk(NULL, "test", 4);
        debug(".\tbassignblk (b = %s, NULL, 1)",
                dumpBstring(b = bfromcstr("")));
        ret += 0 <= (v = bassignblk(b, NULL, 1));
        debug(" = %d; b -> %s", v, dumpBstring(b));
        ret += 0 <= bassignblk(&shortBstring, NULL, 1);
        bdestroy(b);
        return ret;
    }
    len = (int)strlen(str);
    ret += 0 <= bassignblk(NULL, str, len);
    debug(".\tbassignblk (b = %s, \"%s\", %d)",
            dumpBstring(b = bfromcstr("")), str, len);
    ret += 0 > (v = bassignblk(b, str, len));
    debug(" = %d; b -> %s", v, dumpBstring(b));
    ret += 0 != strcmp(bdatae(b, ""), str);
    ret += b->slen != len;
    ret += 0 > bassigncstr(b, "xxxxx");
    bwriteprotect(*b) 
        debug(".\tbassignblk (b = %s, \"%s\", %d)", dumpBstring(b), str,
                len);
    ret += 0 <= (v = bassignblk(b, str, len));
    debug(" = %d; b -> %s", v, dumpBstring(b));
    ret += 0 != strcmp(bdatae(b, ""), "xxxxx");
    ret += ((size_t) b->slen) != strlen("xxxxx");
    bwriteallow(*b)  ret += 0 <= bassignblk(&shortBstring, str, len);
    bdestroy(b);
    debug(".\tbassignblk (a = %s, \"%s\", %d)",
            dumpBstring(&shortBstring), str, len);
    ret += 0 <= (v = bassignblk(&shortBstring, str, len));
    debug(" = %d; a -> %s", v, dumpBstring(&shortBstring));
    return ret;
}

static int test45(void)
{
    int ret = 0;
    debug
        ("TEST: int bassignblk (bstring a, const void * s, int len);");

    /* tests with NULL */ 
    ret += test45_0(NULL);
    ret += test45_0(EMPTY_STRING);
    ret += test45_0(SHORT_STRING);
    ret += test45_0(LONG_STRING);
    debug("\t# failures: %d", ret);
    return ret;
}

static int test46_0(const_bstring r, bstring b, int count,
        const char *fmt, ...)
{
    int ret;
    va_list arglist;
    debug(".\tbvcformata (%s, %d, \"%s\", ...) -> ", dumpBstring(b),
            count, fmt);
    va_start(arglist, fmt);
    ret = bvcformata(b, count, fmt, arglist);
    va_end(arglist);
    debug("%d, %s (%s)", ret, dumpBstring(b), dumpBstring(r));
    if (ret < 0)
        return (NULL != r);
    ret += 1 != biseq(r, b);
    if (0 != ret)
        debug("\t->failed");
    return ret;
}

static int test46_1(bstring b, const char *fmt, const_bstring r, ...)
{
    int ret;
    debug(".\tbvformata (&, %s, \"%s\", ...) -> ", dumpBstring(b),
            fmt);
    bvformata(ret, b, fmt, r);
    debug("%d, %s (%s)", ret, dumpBstring(b), dumpBstring(r));
    if (ret < 0)
        return (NULL != r);
    ret += 1 != biseq(r, b);
    if (0 != ret)
        debug("\t->failed");
    return ret;
}

static int test46(void)
{
    bstring b;
    int ret = 0;
    debug
        ("TEST: int bvcformata (bstring b, int count, const char * fmt, va_list arg);");
    ret += test46_0(NULL, NULL, 8, "[%d]", 15);
    ret += test46_0(NULL, &shortBstring, 8, "[%d]", 15);
    ret += test46_0(NULL, &badBstring1, 8, "[%d]", 15);
    ret += test46_0(NULL, &badBstring2, 8, "[%d]", 15);
    ret += test46_0(NULL, &badBstring3, 8, "[%d]", 15);
    b = bfromcstr("");
    ret +=
        test46_0(&shortBstring, b, shortBstring.slen, "%s",
                (char *)shortBstring.data);
    b->slen = 0;
    ret +=
        test46_0(&shortBstring, b, shortBstring.slen + 1, "%s",
                (char *)shortBstring.data);
    b->slen = 0;
    ret +=
        test46_0(NULL, b, shortBstring.slen - 1, "%s",
                (char *)shortBstring.data);
    debug
        ("TEST: bvformata (int &ret, bstring b, const char * fmt, <type> lastarg);");
    ret += test46_1(NULL, "[%d]", NULL, 15);
    ret += test46_1(&shortBstring, "[%d]", NULL, 15);
    ret += test46_1(&badBstring1, "[%d]", NULL, 15);
    ret += test46_1(&badBstring2, "[%d]", NULL, 15);
    ret += test46_1(&badBstring3, "[%d]", NULL, 15);
    b->slen = 0;
    ret += test46_1(b, "%s", &shortBstring, (char *)shortBstring.data);
    b->slen = 0;
    ret += test46_1(b, "%s", &longBstring, (char *)longBstring.data);
    bdestroy(b);
    debug("\t# failures: %d", ret);
    return ret;
}

int main(int argc, char *argv[]) 
{
    FILE * log_file = fopen("tests/bstr_tests.c", "a+");
    setbuf(log_file, NULL);
    int ret = 0;
    argc = argc;
    argv = argv;
    debug("Direct case testing of bstring core functions");
    ret += test0();
    ret += test1();
    ret += test2();
    ret += test3();
    ret += test4();
    ret += test5();
    ret += test6();
    ret += test7();
    ret += test8();
    ret += test9();
    ret += test10();
    ret += test11();
    ret += test12();
    ret += test13();
    ret += test14();
    ret += test15();
    ret += test16();
    ret += test17();
    ret += test18();
    ret += test19();
    ret += test20();
    ret += test21();
    ret += test22();
    ret += test23();
    ret += test24();
    ret += test25();
    ret += test26();
    ret += test27();
    ret += test28();
    ret += test29();
    ret += test30();
    ret += test31();
    ret += test32();
    ret += test33();
    ret += test34();
    ret += test35();
    ret += test36();
    ret += test37();
    ret += test38();
    ret += test39();
    ret += test40();
    ret += test41();
    ret += test42();
    ret += test43();
    ret += test44();
    ret += test45();
    ret += test46();
    debug("# test bstr failures: %d", ret);
    if (ret > 0) {
        printf("FAILED: %d failures in bstrlib", ret);
    }
    debug("# test aux failures: %d", ret);
    return ret;
}


